Несколько лет назад я сел верстать дашборд. Ничего особенного — просто фиксированная боковая панель, основная область контента и футер. Flexbox казался очевидным выбором, и поначалу всё работало как надо. Но затем я добавил ряд карточек в основную секцию. Вся верстка посыпалась. Следующие три часа я провел в борьбе с коэффициентами flex-grow и вложенными процентными ширинами, наблюдая, как контейнеры отказываются выстраиваться в ряд, сколько бы отступов я ни убирал. Страница казалась башней, которая вот-вот рухнет.

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

Разница в измерениях

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

Grid, с другой стороны, — это план этажа. Он строго двумерен и управляет одновременно и строками, и колонками. Сначала вы определяете структуру, а затем размещаете в ней элементы. Это делает Grid идеальным для общей архитектуры страницы — везде, где вам нужно контролировать вертикальное и горизонтальное позиционирование одновременно. Когда вы пытаетесь навязать сложный двумерный дизайн через вложенные Flexbox-контейнеры, вы в итоге получаете глубокую вложенность разметки, хрупкие обертки и нестабильные расчеты, которые разваливаются, стоит добавить всего один лишний элемент.

Flexbox по-прежнему оправдывает себя

Не спешите заменять каждый flex-контейнер на Grid. Внутри отдельных компонентов Flexbox часто выглядит чище и логичнее. Если у вас есть футер карточки с двумя кнопками, и вы хотите, чтобы одна была прижата к левому краю, а другая — к правому, justify-content: space-between сделает именно то, что вам нужно. Если вам нужно вертикально центрировать иконку внутри кнопки неизвестной высоты, align-items: center — самый простой путь. Переменный контент — например, строка бейджей пользователей с именами разной длины — комфортно вписывается в Flexbox, потому что он работает по принципу «сначала контент». Контейнер адаптируется к тому, что он содержит.

Grid работает по принципу «сначала контейнер». Вы говорите браузеру, сколько существует треков и какого размера они должны быть, а затем помещаете элементы в эти ячейки. Если ваш макет — это всего лишь одна строка элементов, делящих пространство, Grid добавит лишь лишние сложности.

Макет страницы — это задача для Grid

Вот здесь Grid берет управление на себя. Помните мой кошмар с дашбордом? Вот как эта структура должна была выглядеть с самого начала:

.page {
  display: grid;
  min-height: 100vh;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 200px 1fr;
}

.header { grid-row: 1; grid-column: 1 / -1; }
.sidebar { grid-row: 2; grid-column: 1; }
.main { grid-row: 2; grid-column: 2; }
.footer { grid-row: 3; grid-column: 1 / -1; }

Посмотрите, что здесь происходит. Контейнер .page создает три строки и две колонки. Первая строка подстраивает свою высоту под содержимое хедера благодаря auto. Средняя строка занимает всё оставшееся пространство с помощью 1fr. Футер попадает в последнюю строку, размер которой зависит от его собственного контента. Тем временем боковая панель фиксируется на ширине 200 пикселей, а основная область заполняет всё остальное пространство.

Логика позиционирования — это настоящее спасение. Хедер растягивается от линии колонки 1 до линии -1, а это значит, что он растянется на обе колонки, сколько бы колонок вы ни добавили позже. Боковая панель и основной контент делят вторую строку, но занимают разные колонки. Футер возвращается на всю ширину в третьей строке. Вам не нужны процентные расчеты для дочерних элементов. Вам не нужны вложенные обертки, сражающиеся за высоту. Измените ширину боковой панели в одном месте, и основная область подстроится автоматически. Весь макет живет как единая система.

Читаемость с помощью grid-template-areas

Для еще большей ясности вы можете давать названия своим секциям. Вместо того чтобы возиться с номерами линий, вы пишете визуальную карту:

.page {
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
}

.header { grid-area: header; }
.main { grid-area: main; }

Теперь ваш файл стилей читается как вайрфрейм. Если вы когда-нибудь захотите, чтобы на другом брейкпоинте боковая панель появилась справа, вам достаточно поменять местами два слова в строке шаблона. Такую структурную читаемость невозможно достичь внутри башни вложенных flex-контейнеров.

Два суровых урока

Grid — это не магия. Есть две ошибки, которые быстро разрушат ваш макет.

Первая проблема — небрежное использование единиц измерения. Если вы определяете grid-template-columns: 1fr 1fr 1fr, но вашему дизайну требуется всего две колонки контента, третий трек всё равно будет существовать. Он либо останется пустым и создаст неожиданный разрыв, либо заставит ваш основной контент сжиматься так, что это нарушит дизайн. Подходите к этому осознанно. Если вам нужно две колонки, пишите repeat(2, 1fr).