</> Praktum

Главная / CSS / Flexbox

Урок 3 · CSS

Как выстроить блоки с Flexbox

Редакция PraktumОбновлено 20 минут на урок с практикойУровень: новичок

Flexbox — модуль CSS, который раскладывает элементы в ряд или колонку и распределяет свободное место. Контейнеру задают display: flex, детям — как расти и сжиматься. Им собирают меню, шапку и ряд карточек без сложной сетки.

Коротко
  • Flex включают на родителе: display: flex.
  • Главная ось по умолчанию — строка слева направо.
  • flex-grow, flex-shrink и flex-basis решают, как ребёнок растёт и сжимается.
  • Ширина, при которой две карточки ещё в ряд: 2 × flex-basis + gap.
  • Длинное содержимое не даёт карточке сжаться, пока стоит min-width: auto. Разрешить сжатие: min-width: 0.

Зачем этот урок сейчас

Floats и ручные margin больше не нужны, чтобы собрать меню и карточки. Flexbox закрывает девять из десяти учебных макетов: шапка, список ссылок, ряд одинаковых карточек, подвал с колонками. Grid появится следующим уроком, когда понадобится двумерная сетка. Если пропустить оси и базис, любой чужой пример с flex: 1 будет казаться магией.

Минимальный пример

.row {
  display: flex;
  gap: 12px;
}
.row > div {
  background: #e8f0ff;
  padding: 12px;
}

Родителю — display: flex. Детям пока ничего. Они встанут в ряд, высота ряда станет высотой самого высокого ребёнка. gap — промежуток между детьми, без схлопывания как у вертикального margin.

Ось и направление

Главная ось — направление потока. По умолчанию flex-direction: row: слева направо. column складывает сверху вниз. Поперечная ось всегда перпендикулярна. От этого зависят justify-content и align-items: первый двигает по главной, второй — по поперечной. Если «выровнять по центру» не сработало, ты скорее всего крутишь не ту ось.

.stack { display: flex; flex-direction: column; gap: 8px; }

flex-grow, flex-shrink, flex-basis

Три свойства ребёнка — вся математика Flexbox. flex-basis — стартовый размер вдоль главной оси, до роста и сжатия. flex-grow — кто забирает свободное место: 0 не растёт, 1 растёт. flex-shrink — кто отдаёт место, когда его не хватает: 0 не сжимается, 1 сжимается. Короткая запись: flex: grow shrink basis.

.card { flex: 1 1 242px; }

Читать так: можешь расти, можешь сжиматься, начни с 242 пикселей. Именно базис участвует в решении «влезут ли двое в ряд».

Выравнивание и align-content

justify-content — главная ось: начало, центр, конец, space-between. align-items — поперечная: stretch по умолчанию, center, flex-start. Когда строк несколько (flex-wrap: wrap), появляется align-content: он распределяет сами строки в поперечном направлении. Без переноса align-content почти ничего не делает — новички часто крутят его зря.

Порядок и шапка с margin-left: auto

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

.header {
  display: flex;
  align-items: center;
  gap: 16px;
}
.header nav {
  margin-left: auto;
}

margin-left: auto в flex-ряду съедает всё свободное место слева и прижимает навигацию к правому краю. Это стандартный приём, не хак. Свойство order меняет визуальный порядок детей: чем больше число, тем правее или ниже. В HTML порядок для клавиатуры остаётся прежним — поэтому order не заменяет продуманную разметку.

Ряд карточек и ширина переноса

Две карточки остаются в одном ряду, пока хватает ширины контейнера. Правило:

ширина переноса = 2 × flex-basis + gap. Пример: базис 242px и gap 16px дают 500px. Уже на 499px вторая карточка переносится. Если взять базис 220px и тот же gap, перенос случится только на 456px.

.cards { display: flex; flex-wrap: wrap; gap: 16px; }
.card { flex: 1 1 242px; }

Почему карточка не сжимается и вылезает

У flex-элемента по умолчанию min-width: auto: он не станет уже своего содержимого. Длинный URL, таблица, блок pre или широкая картинка держат карточку, и она вылезает из ряда. Поставь min-width: 0 (или overflow: auto), чтобы сжатие заработало.

Что смотреть в DevTools

  1. Выбери контейнер в Elements. В стилях должна быть строка display: flex.
  2. В Chrome открой значок Flex: поверх страницы нарисуются оси и gap.
  3. Кликни ребёнка: смотри computed flex-grow, flex-shrink, flex-basis, min-width.
  4. Если min-width равен ширине длинного слова — вот причина вылезания.
  5. Меняй ширину экрана и смотри, когда computed width ребёнка падает ниже 2 × basis + gap.

Flexbox или Grid

Flexbox

Один ряд или колонка, шапка, меню, карточки в ленту, распределение пустого места.

Grid

И строки, и колонки сразу: макет всей страницы, галерея с выравниванием по двум осям.

Частые ошибки

  • Включили flex на каждом ребёнке, а не на родителе.
  • Считают перенос «на глаз», а не как 2 × basis + gap.
  • Ждут сжатия карточки, пока у неё min-width: auto и длинное содержимое.
  • Крутят align-content на одном ряду.
  • Ломают Tab через order без нужды.

Доступность

Визуальный порядок должен совпадать с порядком в HTML, если человек идёт Tab. Карточки-ссылки не делай вложенными интерактивными блоками. На узком экране столбик читается сверху вниз — проверь, что смысл не зависит от «было слева — стало справа».

Поддержка браузерами

Flexbox поддерживается во всех актуальных браузерах. Старый синтаксис 2009 года больше не пиши. Смотри таблицу caniuse по модулю Flexible Box, если нужно поддержать древний WebView.

align-self и исключение из ряда

Иногда одна карточка должна прижаться к верху, а остальные растянуться. Родителю оставляют align-items: stretch, ребёнку ставят align-self: flex-start. Это исключение, не новое свойство оси. То же с flex-grow: 0 у логотипа: он не должен раздуваться, когда меню забирает свободное место.

В шапке ссылкам не ставь flex-grow: 1: растянется пустая зона и станет кликабельной. Для меню хватает gap и margin-left: auto у nav.

Собери шапку и карточки

Собери шапку с логотипом и nav через margin-left: auto. Затем три карточки: flex: 1 1 242px и gap: 16px. В DevTools сузь окно ниже 2 × 242 + 16 — карточки перенесутся. Вставь в карточку длинный URL, посмотри min-width и поставь min-width: 0. На одной карточке задай order: -1 и пройди Tab: фокус пойдёт по HTML, а не по экрану.

Практика

Собери три карточки. Контейнер: display: flex; flex-wrap: wrap; gap: 16px. Карточка: flex: 1 1 242px. Внутри карточки длинное слово или ссылка. Проверь: при ширине 500px и больше — две (или три) в ряд, при 499px — перенос. Затем добавь min-width: 0 и сравни, перестаёт ли текст вылезать. Собери шапку: логотип и nav с margin-left: auto.

Открыть песочницу

Частые вопросы

Почему карточка вылезает из ряда?

У flex-элемента по умолчанию min-width: auto: он не уже своего содержимого. Длинное слово, картинка или блок pre не дают сжаться. Поставь min-width: 0 или overflow: auto.

Как посчитать, когда две карточки перенесутся?

Ширина переноса = 2 × flex-basis + gap. Для базиса 242px и промежутка 16px это 500px. Ниже этого значения вторая карточка уходит на новую строку.

Чем flex: 1 отличается от flex: 1 1 242px?

flex: 1 раскрывается в 1 1 0%: базис ноль, свободное место делится поровну независимо от содержимого. Запись flex: 1 1 242px задаёт стартовую ширину 242px — от неё считают перенос и рост.

Когда нужен Grid?

Когда есть и строки, и колонки: страница целиком, галерея с выравниванием по двум осям. Flexbox — ряд или колонка плюс распределение свободного места.

Зачем order, если можно переставить HTML?

Визуальный порядок меняют редко: скринридер и Tab идут по HTML. order полезен, когда на узком экране логотип должен оказаться над меню, но в коде логичнее оставить меню вторым. Не используй order как основную раскладку.

Источники