Flexbox: sticky footer

Sticky footer — паттерн, при котором footer страницы всегда находится внизу viewport, даже если контент страницы короткий.

Зачем нужно

Без специальной обработки footer "всплывает" в середину страницы при малом контенте. Flexbox решает это элегантно: страница — вертикальный flex-контейнер, основной контент получает flex: 1 и растягивается, прижимая footer вниз. Это самое простое и надёжное решение проблемы.

Где используется

  • Любой сайт с header/content/footer структурой
  • Лендинги и одностраничные сайты
  • Страницы входа, регистрации, ошибок (404)
  • Любая страница где мало контента на некоторых условиях

Основной контент

Метод 1: flex: 1 на main

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
}

main {
  flex: 1; /* Занимает всё оставшееся место */
}
<body>
  <header>Header</header>
  <main>Content</main>
  <footer>Footer</footer>
</body>
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
}

footer {
  margin-top: auto; /* Поглощает всё свободное место сверху */
}

Метод 3: flex-grow на wrapper

.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.page__content {
  flex-grow: 1;
}
<div class="page">
  <header class="page__header">Header</header>
  <div class="page__content">
    <main>Main</main>
    <aside>Sidebar</aside>
  </div>
  <footer class="page__footer">Footer</footer>
</div>

Полный рабочий пример

*, *::before, *::after { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
}

.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.page__header {
  background: #0070f3;
  color: white;
  padding: 16px 32px;
}

.page__main {
  flex: 1;
  padding: 32px;
}

.page__footer {
  background: #333;
  color: white;
  padding: 16px 32px;
  text-align: center;
}

Частые ошибки

  • height: 100% вместо min-height: 100vhheight: 100% не работает без явной высоты у родителей по всей цепочке
  • flex: 1 без flex-direction: column — по умолчанию flex-direction: row; нужно явно указать column
  • Не указан margin: 0 на body — браузерный margin на body может добавить лишние прокрутки
  • 100vh и мобильный браузер — адресная строка меняет 100vh; для мобильных предпочтительнее 100svh

Связанные темы

Ресурсы