Flexbox (Flexible Box Layout) - режим CSS для расположения элементов в строку или колонку с гибким распределением места между ними. Достаточно включить его свойством display: flex на родителе - и его прямые потомки сами выстроятся в ряд, без ручного расчёта отступов и без старых приёмов вроде float.
В этом уроке
Попробуй прямо сейчас: убери строку display: flex у .container - три блока встанут друг под другом, как обычные div. Верни её обратно - они снова выстроятся в ряд и растянутся на всю высоту контейнера.
Зачем нужен Flexbox: какую проблему он решает
До Flexbox расположить несколько элементов в ряд с равными промежутками или точно отцентрировать блок по вертикали приходилось через float с ручным расчётом отступов в процентах, через inline-block с побочными "фантомными" пробелами между элементами или через таблицы. Любое изменение ширины экрана или количества элементов означало пересчитывать отступы заново. Flexbox решает это декларативно: браузер сам распределяет свободное место, выравнивает элементы по вертикали и горизонтали и подстраивается под изменение количества элементов - без единого пересчёта вручную.
display: flex; на родителе - элементы внутри сами встают в ряд и делят место между собой.
float: left; на каждом элементе по отдельности, с margin-right: 2% и подбором чисел, чтобы блоки не переносились - хрупкий способ, ломается при любом изменении количества элементов.
Как включить Flexbox: контейнер и его элементы
Свойство display: flex (или display: inline-flex, если сам контейнер должен вести себя как строчный элемент) ставится на РОДИТЕЛЯ - он становится flex-контейнером. Flex-элементами при этом становятся только его ПРЯМЫЕ потомки, а не вложенные глубже элементы: если внутри flex-элемента есть свой div с содержимым, этот вложенный div flex-элементом не является и по flex-правилам не выравнивается. Здесь же появляется важное разделение: одни свойства (например, justify-content, align-items, flex-wrap) относятся к контейнеру и пишутся на нём, а другие (flex-grow, flex-shrink, align-self) относятся к элементам и пишутся на них - в следующих уроках группы разберём каждое по отдельности.
.container { display: flex; } - прямые дочерние элементы .container становятся flex-элементами.
.container .item .nested { justify-content: center; } - justify-content задан на элементе, вложенном глубже прямых потомков контейнера, эффекта не будет.
Главная и поперечная ось: как элементы расположены по умолчанию
У flex-контейнера всегда есть две оси: главная (main axis) - направление, в котором выстраиваются элементы, и поперечная (cross axis) - перпендикулярная ей. Направление главной оси задаётся свойством flex-direction, а по умолчанию, если это свойство вообще не указывать, действует flex-direction: row - элементы идут в строку слева направо. Ещё два умолчания важны с самого начала: flex-wrap: nowrap - элементы не переносятся на новую строку, при нехватке места они сжимаются или вылезают за контейнер; и align-items: stretch - если элементу не задана явная высота, он растягивается на всю высоту контейнера по поперечной оси.
.container { display: flex; } - без flex-direction элементы уже выстроятся в строку (row - значение по умолчанию).
.container { display: flex; flex-direction: row; } - flex-direction: row не ошибка, но и не нужна: это и так значение по умолчанию, писать его явно избыточно.
Частые ошибки новичков
| Ошибка | Что происходит | Как исправить |
|---|---|---|
| Пишут justify-content или align-items на дочернем элементе вместо контейнера | Свойство не действует, расположение элементов не меняется | Все выравнивающие свойства контейнера писать на элементе с display: flex, а не на его детях |
| Ждут, что flex-элементами станут вообще все вложенные элементы | Элементы глубже прямых потомков не выравниваются по flex-логике | Помнить: flex-элементы - только прямые потомки контейнера; для вложенной группы нужен свой display: flex |
| Копируют старый код с display: box или box-orient из статей десятилетней давности | Свойства не поддерживаются современными браузерами, эффекта нет | Использовать современный синтаксис: display: flex и flex-* свойства без префиксов |
| Не понимают, почему блок растянулся на всю высоту контейнера сам по себе | Кажется багом, хотя это ожидаемое поведение | Помнить про align-items: stretch по умолчанию - если высота не задана явно, элемент растягивается |
Шпаргалка
| Что нужно | Как сделать |
|---|---|
| Включить Flexbox (блочный контейнер) | display: flex; |
| Включить Flexbox (строчный контейнер) | display: inline-flex; |
| Кто становится flex-элементом | только прямые потомки контейнера |
| Направление главной оси по умолчанию | flex-direction: row (слева направо) |
| Перенос элементов по умолчанию | flex-wrap: nowrap (без переноса) |
| Высота элементов по умолчанию | align-items: stretch (растягиваются на всю высоту контейнера) |
Коротко: отвечаем на вопросы
Чем Flexbox отличается от CSS Grid?
Flexbox работает вдоль одной оси - строки или колонки - и хорошо подходит, когда элементы нужно распределить в одном направлении: в ряд или в столбец. CSS Grid управляет сразу двумя измерениями - строками и колонками одновременно, поэтому лучше подходит для полноценной сетки. Для одного ряда карточек обычно проще Flexbox, а для сложной сетки с несколькими строками и столбцами - Grid.
Почему flexbox не работает, хотя display: flex написан?
Чаще всего дело не в самом display: flex, а в том, где написаны остальные свойства. justify-content, align-items, flex-direction и flex-wrap действуют, только если их задать на самом контейнере - том элементе, у которого стоит display: flex. Если эти свойства случайно написаны на дочерних элементах, они просто ничего не делают.