belun.app Блог
EN

CSS Flexbox: главная и поперечная ось и когда его применять

Как на самом деле работает flexbox — главная и поперечная ось, justify-content против align-items, wrap, gap и когда лучше взять grid.

Веб-дизайнер расставляет прямоугольные блоки макета на экране компьютера в рабочем пространстве

Почти любой баг с flexbox, который мне приходилось разбирать, сводится к одному: с какой осью я сейчас работаю. justify-content: center не действует, align-items тоже, и в итоге оказывается, что нужно было просто поменять их местами. Как только это укладывается в голове, flexbox перестаёт быть игрой в угадайку.

Если хочется не читать, а покликать, в Генераторе Flexbox можно переключать каждое свойство и сразу видеть, как перестраивается ряд блоков. А здесь разберём, что там происходит на самом деле.

Есть две оси, и направление решает, какая из них какая

Сам по себе display: flex визуально почти ничего не делает. Настоящая работа начинается с flex-direction — он задаёт главную ось (по умолчанию строка, слева направо). Всё остальное определяется относительно этой оси, а не относительно экрана.

  • justify-content работает вдоль главной оси
  • align-items работает вдоль поперечной, перпендикулярной ей

Переключите flex-direction со row на column — и главная ось повернётся на 90 градусов. justify-content: center, который раньше центрировал по горизонтали, теперь центрирует по вертикали, а align-items меняется местами и работает по горизонтали. Сами свойства не изменились; изменилась ось под ними. Именно это объясняет большинство вопросов вида «flexbox не работает», которые встречаются на форумах.

У justify-content шесть значений, которые стоит знать

  • flex-start — по умолчанию, элементы прижимаются к началу
  • flex-end — элементы прижимаются к концу
  • center — элементы собираются в середине
  • space-between — первый и последний элемент касаются краёв, оставшееся пространство делится поровну между остальными
  • space-around — у каждого элемента поровну места с обеих сторон, поэтому у крайних элементов промежуток визуально в два раза меньше, чем у средних
  • space-evenly — абсолютно все промежутки, включая внешние края, равны

Чаще всего берут space-between, а потом удивляются, почему у краёв отступы теснее, чем между элементами. Так и должен вести себя space-around. Если нужны одинаковые отступы везде — берите space-evenly, а не space-around.

align-items: stretch — значение по умолчанию, и его не видно, пока не увидишь

stretch применяется, если align-items вообще не задан, и заметен только когда у элемента нет фиксированного размера по поперечной оси. Задайте каждому элементу явную height в строке — и stretch делать нечего, элементы и так заполняют то пространство, которое им отвели. Уберите высоту, и все элементы вдруг растянутся на всю высоту контейнера. Выглядит так, будто свойство «заработало», хотя на самом деле оно работало всё это время.

wrap превращает переполнение в новую строку вместо сжатия

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

Это и есть лекарство от классического бага «на мобильном элементы стали нечитаемо узкими». В девяти случаях из десяти контейнеру просто не хватало flex-wrap: wrap.

Для отступов — gap, а не margin

.container {
  display: flex;
  gap: 12px;
}

gap добавляет отступ строго между элементами: ничего не появляется перед первым или после последнего, поэтому больше не нужен трюк вида :last-child { margin-right: 0 }. Все основные браузеры поддерживают gap во flexbox с начала 2021 года — и я до сих пор вижу, как его избегают по привычке, а не по необходимости.

Flexbox или grid?

Flexbox одномерный: он выстраивает строку или колонку и отдаёт размер на откуп контенту — то, что нужно навигации, ряду кнопок или внутренней раскладке карточки. Grid двумерный и оправдывает себя, когда нужен контроль и над строками, и над колонками сразу: каркас страницы, галерея, дашборд. Я по умолчанию беру flexbox и переключаюсь на grid только тогда, когда ловлю себя на попытке выровнять что-то сразу по двум измерениям.

Поиграйте со свойствами в Генераторе Flexbox — переключайте направление, justify и align, пока превью не станет таким, как задумано, и копируйте готовый CSS контейнера.

Попробуйте инструмент

Генератор Flexbox →