CSS · Урок 6

Flexbox и CSS Grid

Две главные технологии раскладки. Flexbox растягивает элементы один за другим, а Grid строит сетку из строк и колонок.

Flexbox: выравнивание одного измерения

Flexbox отлично подходит для меню, строк кнопок, карточек в ряд. Контейнеру задаём display: flex — и его дети выстраиваются в линию.

.nav-row {
  display: flex;
  justify-content: space-between; /* основная ось */
  align-items: center;           /* поперечная ось */
  gap: 12px;
}
Лого
Главная · О нас · Контакты
Кнопка

Свойства для родителя:

Для детей:

.card { flex: 1; }        /* растёт и занимает место */
.side { flex: 0 0 200px; } /* фиксированная ширина */
.grow { flex-grow: 2; } /* слайдер роста */
💡
Психологический трюк: justify-content: center + align-items: center на display:flex-контейнере — самый быстрый способ отцентрировать блок по вертикали и горизонтали.

CSS Grid: сетка двух измерений

Grid создаёт «шахматку»: задаём колонки и строки — элементы раскладываются автоматически.

.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
1
2
3
4
5
6

Полезные приёмы:

.layout {
  display: grid;
  grid-template-columns: 200px 1fr;      /* боковая + контент */
  grid-template-rows: auto auto;
}

.area-header  { grid-column: 1 / -1; }            /* на всю ширину */
.item          { grid-row: 1 / 3; }               /* через 2 строки */
.area          { grid-area: 2 / 2 / 3 / 3; }  /* строка/колонка */

Адаптивность через media queries

Сетка подстраивается под ширину экрана с помощью @media:

.grid { grid-template-columns: 1fr; }

@media (min-width: 768px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1024px) {
  .grid { grid-template-columns: repeat(4, 1fr); }
}
ℹ️
Правило мобильных устройств — «mobile-first»: сначала пишут стили для узкого экрана и добавляют min-width-брейкпоинты по мере увеличения. Так стилей меньше и они проще.

Когда что выбирать

СитуацияИнструмент
Меню, кнопки, карточки в рядFlexbox
Галерея, плитка, сетка товаровGrid
Шапка + сайдбар + контентGrid
Что-то отцентрироватьFlexbox

flex-direction и направление осей

По умолчанию Flexbox раскладывает элементы слева направо (горизонтальная «главная ось»). Ось легко повернуть:

.row    { flex-direction: row; }         /* слева направо (по умолчанию) */
.column { flex-direction: column; }      /* сверху вниз */
.rev    { flex-direction: row-reverse; }  /* справа налево */
💡
После смены направления меняются и оси: justify-content теперь работает вертикально, а align-items — горизонтально. Полезный трюк для вертикального центрирования.

flex-wrap и свободное место

Если детей много, они сжимаются. Включите перенос flex-wrap: wrap — и всё, что не влезло, уйдёт на новую строку:

.tools {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.tool { flex: 0 0 150px; }  /* 0 0 = не растягивается и не сжимается, базовая 150px */
ℹ️
flex: 1 1 0 — «расти на равных»; flex: 0 0 auto — «по своему размеру»; flex: 1 — удобное сокращение «расти и занимать равную долю».

grid-template-areas

Самый читаемый способ описать макет — нарисовать его строками-именами. Каждая строка кавычек = ряд сетки:

.layout {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "header header"
    "sidebar content"
    "footer footer";
  gap: 12px;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer  { grid-area: footer; }
💡
Точка . в схеме означает «пустая ячейка». Имена нельзя повторять в несмежных ячейках — сетка просто не соберётся.

auto-fit / auto-fill и minmax()

Сетка может сама решать, сколько помещается колонок, если использовать авто-повтор вместе с минимальной и максимальной шириной:

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}

Это значит: минимум колонки 220px, максимум — 1fr. Сколько поместится на экране, столько и будет, без media queries.

ℹ️
auto-fill заполняет сетку «пустышками» до конца строки, auto-fit — растягивает существующие колонки. Итоговое поведение видно наглядно, но для карточек почти всегда выбирают auto-fit.

order: расстановка по смыслу

Визуальный порядок элементов можно менять без перестановки в HTML. Свойство order работает и во Flexbox, и в Grid:

.author   { order: 1; }   /* покажется первым */
.content  { order: 2; }
.comments { order: 3; }
⚠️
Не злоупотребляйте order: порядок табуляции с клавиатуры остаётся HTML-ным. Если важна доступность, сохраняйте смысловой порядок в разметке.

space-evenly и распределение места

У justify-content три близнеца по распределению «воздуха»: space-between (по краям впритык), space-around (зазоры с боков) и space-evenly (равные отступы везде):

.row {
  display: flex;
  justify-content: space-evenly;   /* все промежутки строго равны */
  justify-content: space-around;   /* у краёв половинный зазор */
  justify-content: space-between;  /* крайние прижаты к границам */
}
ℹ️
Почти всегда «между» похоже на то, что хотел дизайнер. Если вдруг кажется «криво» — попробуйте другого близнеца, они решают 95% вопросов выравнивания.

align-content: строки и переносы

Когда элементов много и родитель переносит их на новые строки, за вертикальное распределение этих строк отвечает align-content:

.tags {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;    /* строки сверху */
  align-content: center;        /* по центру между рядами */
  align-content: flex-end;      /* прижато вниз */
  gap: 8px;
}
💡
Короткая мнемоника: align-items — внутри одного ряда, align-content — между рядами.

grid-auto-flow: dense и мозаика

Если элемент не влезает в ячейку, Grid сделает «дыру». Флаг dense заполняет дыры последующими элементами — получается мозаика без пустот:

.mosaic {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-flow: dense;      /* дыры добиваются элементами позже */
  gap: 10px;
}

.wide  { grid-column: span 2; }   /* на две колонки */
.tall  { grid-row: span 2; }      /* на две строки */
⚠️
Будьте осторожны: dense меняет визуальный порядок элементов. Для галерей, где порядок не критичен, — идеально.

Flexbox: margin-left: auto

Внутри flex-контейнера margin: auto поглощает лишнее пространство и прижимает элемент к противоположной стороне:

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

.spacer { margin-left: auto; }   /* всё, что правее, уедет вправо */
💡
Два «режима» правого края: justify-content: space-between на родителе и margin-left: auto на конкретном ребёнке. Второй точнее, когда групп элементов несколько.

Связка Grid + Flex: карточка

Реальные макеты почти всегда сетка снаружи и flex внутри карточки:

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
}

.card {
  display: flex;
  flex-direction: column;      /* тело в столбик */
}

.card .btn {
  margin-top: auto;            /* кнопка прижата к низу */
}
ℹ️
Классика «низ колонки»: margin-top: auto внутри flex-колонки опускает дочерний блок к нижнему краю независимо от длины контента выше.

Оси на практике

Главная ось — куда смотрят элементы, поперечная — им навстречу:

.row {
  display: flex;
  flex-direction: row;      /* главная ось: слева направо */
  justify-content: center;  /* по главной оси */
  align-items: center;      /* по поперечной оси */
}
ℹ️
Смена flex-direction меняет и место «главное»: при column главная ось — вертикаль, и justify-content двигает блоки вверх-вниз.

flex-flow: направление + перенос

Одно свойство объединяет направление и разрешение переноса:

.cards {
  display: flex;
  flex-flow: row wrap;      /* строка · можно переноситься */
}

flex: универсальная запись

Три числа: рост — сужение — базис:

.item {
  flex: 1 1 200px;   /* растёт · может ужаться · идеал 200px */
}
💡
Короткая запись flex: 1 равняется flex: 1 1 0%. Это «расти поровну» — самый частый рецепт.

flex-basis 0 — равные колонки

Если базис нулевой, ширина зависит только от коэффициента роста:

.col          { flex: 1 1 0%; }   /* все одинаковой ширины */
.col--wide  { flex: 2; }           /* в два раза шире соседей */

align-content: ряды внутри

Когда строк несколько, распределять их помогает align-content:

.grid-lite {
  display: flex;
  flex-wrap: wrap;
  align-content: space-between;   /* ряды: растянуты по высоте */
}

Фиксированный сайдбар

Не дайте боковой панели сжиматься, контенту — расти:

.layout {
  display: flex;
  gap: 16px;
}
.content { flex: 1; }              /* забирает свободное */
.aside   { flex: 0 0 240px; }  /* зафиксирован 240px */

Иконка в квадрате

Любой блок можно центрировать целиком, без пиксельных отступов:

.icon-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
}

Порядок: order

order переставляет детей без правки HTML:

.item-1 { order: 3; }
.item-2 { order: 1; }   /* будет первым */
.item-3 { order: 2; }
⚠️
Доступность и скринридеры читают документ в порядке разметки, а не order. Меняйте порядок в HTML, если важен порядок чтения.

Футер прижат к низу

Классика flexbox: контент тянется, футер держится у нижней кромки:

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
main   { flex: 1; }   /* занимает свободное место */
footer { flex: 0 0 auto; }
💡
Хотите «дышать» — добавьте на main паддинги, а не отступы по body. Футер гарантированно внизу.

gap в колонках

Промежуток действует и по направлениям — в столбиках то же самое:

.stack {
  display: flex;
  flex-direction: column;
  gap: 12px;   /* равные промежутки между абзацами */
}

Почему «схлопывается»?

Длинный текст в flex ряду внезапно вылезает. Частый виновник — контент:

.cut-text {
  min-width: 0;       /* позволяем содержимому сжиматься */
  overflow-wrap: anywhere;
}
ℹ️
У flex-детей есть подразумеваемый min-width: auto, который не даёт сжаться втройне. Укажите min-width: 0 — и текст перенесётся по словам.

Инпут + кнопка в один ряд

Классика верстки поиска: поле тянется, кнопка фиксированной ширины:

.search { display: flex; gap: 8px; }
.search input { flex: 1; min-width: 0; }
.search button { flex: 0 0 auto; }

Тренировка

  1. Соберите строку меню из 4 ссылок через Flexbox с justify-content: space-between.
  2. Сделайте галерею из 6 фото с repeat(3, 1fr).
  3. На узком экране превратите галерею в 1fr через media query.
  4. Попробуйте «липкий» сайдбар: position: sticky; top: 20px.