Урок 3 · CSS
Как выстроить блоки с Flexbox
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
- Выбери контейнер в Elements. В стилях должна быть строка display: flex.
- В Chrome открой значок Flex: поверх страницы нарисуются оси и gap.
- Кликни ребёнка: смотри computed flex-grow, flex-shrink, flex-basis, min-width.
- Если min-width равен ширине длинного слова — вот причина вылезания.
- Меняй ширину экрана и смотри, когда computed width ребёнка падает ниже 2 × basis + gap.
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 как основную раскладку.