Макет сайта на флексбоксах

Флексбоксы идеально подходят для создания широко используемых макетов веб-сайтов, вроде трёхколоночного, так называемый макет «Святой Грааль», где все колонки должны занимать полную высоту, независимо от их содержимого. При этом в исходном коде основное содержимое идёт до навигации, а на самой странице основное содержимое идёт после навигации.

Вроде этого.

<!doctype html>
<title>Пример</title>
<style>
* {
  box-sizing: border-box; 
}
body {
  margin: 0;
}
#main {
  display: flex;
  min-height: calc(100vh - 40vh);
}
#main > article {
  flex: 1;
}
#main > nav, 
#main > aside {
  flex: 0 0 20vw;
  background: beige;
}
#main > nav {
  order: -1;
}
header, footer, article, nav, aside {
  padding: 1em;
}
header, footer {
  background: yellowgreen;
  height: 20vh;
}
</style>
<body>
  <header>Шапка</header>
  <div id="main">
    <article>Статья</article>
    <nav>Навигация</nav>
    <aside>Боковая панель</aside>
  </div>
  <footer>Подвал</footer>
</body>

До появления флексбоксов такой макет было довольно трудно получить без использования каких-либо хаков. Разработчикам часто приходилось делать такие вещи, как добавление дополнительной разметки, применение отрицательных margin и другие трюки, чтобы всё правильно выстраивалось независимо от объёма содержимого или размера экрана. Но, как показывает приведённый выше пример, на флексбоксах всё получается гораздо проще.

Вот краткое изложение кода. В данном примере мы делаем элемент #main флекс-контейнером, а шапку и подвал оставляем блочными элементами. Другими словами, флексбоксом становится только средняя часть. Вот фрагмент, который делает её флекс-контейнером.

#main {
  display: flex;
  min-height: calc(100vh - 40vh);
}

Просто используем display: flex, чтобы сделать флекс-контейнер. Обратите внимание, мы также задаём значение min-height с помощью функции calc() и устанавливаем #main как 100% от высоты области просмотра минус высота шапки и подвала (по 20vh каждый). Это гарантирует, что макет будет занимать всю высоту экрана, даже если в нём мало содержимого. В итоге подвал никогда не поднимется и не оставит пустого пространства под ним, если содержимое занимает меньше высоты экрана.

Вычисление min-height было достаточно простым, учитывая, что мы применили box-sizing: border-box ко всем элементам. Если бы мы этого не сделали, тогда нужно было бы добавить значение padding к сумме для вычитания.

После установки флекс-контейнера мы имеем дело с флекс-элементами.

#main > article {
  flex: 1;
}
#main > nav,
#main > aside {
  flex: 0 0 20vw;
  background: beige;
}
#main > nav {
  order: -1;
}

Свойство flex является сокращением для свойств flex-grow, flex-shrink и flex-basis. В первом случае мы написали только одно значение, поэтому flex устанавливает свойство flex-grow. Во втором случае мы написали все три значения для <nav> и <aside>, чтобы установить нулевое значение flex-grow, нулевое значение flex-shrink и значение 20vw для flex-basis. Свойство flex-basis устанавливает исходный основной размер флекс-элемента до распределения свободного пространства. Таким образом, мы просто устанавливаем ширину <nav> и <aside>, а также их цвет фона.

Вот и весь код, благодаря которому макет работает.

В этом примере флексбоксы применяются только для центрального раздела, где располагается основное содержимое. Если вы желаете использовать флексбоксы для всей страницы, то можете добавить вложенные флекс-контейнеры.

Автор и редакторы

Автор: Йен Диксон
Последнее изменение: 22.11.2019
Редакторы: Влад Мержевич
Курс по вёрстке сайта на CSS Grid