Flexbox и CSS Grid: раскладка сайта

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

Уровень: средний 14 разделов 2–3 часа

1. Одна ось усиливает, две — побеждают: когда flex, когда grid

Перед тем как писать код, пойми ключевое различие. Flexbox — одномерная раскладка: он работает с одним направлением — рядом или колонкой. Grid — двухмерная раскладка: он управляет колонками и рядами одновременно.

FlexboxGrid
одна осьдве оси: колонки и ряды
ряд или колонкаполноценная сетка
размер элементов зависит от содержимогоразмер зависит от ячеек сетки
панели, шапки, кнопки, карточки в рядкаркас страницы, галереи, дашборды

Практическое правило: flex — для панелей, grid — для страниц. Если нужно выстроить несколько элементов в линию и не важно, как разделится место между ними, — бери flexbox. Если раскладываешь контент по строкам и колонкам одновременно — бери grid.

Инструменты не конкурируют, они дополняют друг друга: наружный каркас страницы удобно собрать на Grid, а внутри каждой ячейки — использовать flexbox для выравнивания ряда кнопок или карточек. Это нормальная, рабочая практика.
/* каркас страницы — grid */
.page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-areas: "header header" "sidebar main" "footer footer";
}

/* внутренности ячеек — flex */
.toolbar { display: flex; gap: 12px; }

2. Flexbox: оси и главный контейнер

Flexbox включается свойством display: flex на родительском элементе — он становится flex-контейнером, а его прямые дети — flex-элементами. Дальше контейнер решает, как расположить детей.

.toolbar {
  display: flex;
  /* row — элементы в ряд (по умолчанию), column — в колонку */
  flex-direction: row;
}

У flex-контейнера две оси:

Смена направления через flex-direction: row-reverse или column-reverse разворачивает порядок элементов — удобно, когда нужно зеркалировать меню без правки разметки.

.menu {
  display: flex;
  flex-direction: row-reverse;
  /* пункты пойдут справа налево */
}
Отдельное значение — display: inline-flex. Контейнер останется flex, но сам поведёт себя как строчный элемент: его ширина будет равна содержимому и он встанет в поток текста. Полезно для маленьких лейблов и чипов.

3. Выравнивание в flex

Главные свойства выравнивания в flexbox — по паре на каждую ось. justify-content распределяет элементы вдоль главной оси, align-items — вдоль поперечной.

.toolbar {
  display: flex;
  /* главная ось: от начала до конца, равномерно, с пробелами… */
  justify-content: start | center | space-between | space-around | space-evenly;
  /* поперечная ось: растянуть, по центру, к краям… */
  align-items: stretch | center | flex-start | flex-end;
}

Отдельный элемент можно выравнивать независимо от остальных через align-self. Классическая задача — шапка сайта: логотип слева, кнопки справа, всё по центру по высоте.

/* кнопки в шапке: логотип слева, действия справа, всё по центру */
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 20px;
}
Меняй justify-content на space-around или space-evenly в примере выше и смотри, как меняются зазоры между кнопками.

4. Гибкость элементов

У flex-элементов три свойства «растяжимости». Вместе они отвечают на вопрос: как элемент ведёт себя, когда место есть или когда его не хватает.

.card { flex: 1 1 0; }
/* равно: grow 1, shrink 1, basis 0.
   Все карточки стартуют с нуля и делят место поровну. */

Сокращение flex: 1 1 0 — самый частый вариант «равных карточек». С ним три карточки в ряду занимают одинаковую ширину независимо от содержимого: лишнее место распределяется одинаковыми долями.

.cards { display: flex; gap: 16px; }
.card {
  flex: 1 1 0;
  background: #f1f5f9;
  padding: 20px;
  border-radius: 10px;
}

Порядок отображения меняется свойством order: по умолчанию все элементы имеют order: 0, элементы с меньшим значением идут раньше. Порядок в DOM не меняется — это не влияет на доступность и поисковую индексацию.

.main-news { order: -1; }   /* выдвинуть на первое место */
.aside-news { order: 2; }   /* опустить в конец */
Не используй order для перестановки смысловых блоков, например чтобы главный заголовок визуально шёл раньше, чем в разметке. Скринридер и пользователь с тач-навигацией будут двигаться по порядку DOM, а не по картинке.

5. Перенос и промежутки

По умолчанию flex-элементы стараются поместиться в одну строку. Когда элементов много, включай перенос: flex-wrap: wrap. Перенесённые строки дополнительно распределяются по поперечной оси свойством align-content.

.chips {
  display: flex;
  flex-wrap: wrap;      /* элементы будут переноситься */
  gap: 8px;             /* зазор и внутри строки, и между ними */
  align-content: flex-start;
}

Свойство gap задаёт промежутки между элементами в обеих системах — flex и grid. Это большой плюс: не нужно обнулять маргины у крайних элементов и писать хак с отрицательными отступами.

/* теги-чипы: ряд с переносом и одинаковыми зазорами */
.chips span {
  padding: 4px 12px;
  border-radius: 999px;
  background: #e2e8f0;
  font-size: 14px;
}
gap поддерживается во всех современных браузерах — смело используй его вместо margin на дочерних элементах. Исключение — очень старые браузеры, где придётся рисовать зазоры через классы .chips > * + * { margin-left: 8px }.

6. Flexbox: практические приёмы

Идеальное центрирование

.holder {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

Так центрируется любой блок по обеим осям — три строки вместо табличной вёрстки и абсолютных позиций.

Липкий подвал через flex на body

html, body { min-height: 100vh; }
body {
  display: flex;
  flex-direction: column;
  margin: 0;
}
.footer {
  margin-top: auto;  /* подвал прижимается к низу, даже если контента мало */
}

Кнопка с иконкой

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
}
/* иконка и текст выстроятся в одну линию и не разъедутся */

Счётчик в бейдже

/* «Уведомления» с круглым счётчиком в углу кнопки */
.badge {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
}
.badge-count {
  position: absolute;
  top: -6px; right: -6px;
  min-width: 18px; height: 18px;
  padding: 0 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: #ef4444;
  color: #fff;
  font-size: 12px;
}
display: inline-flex плюс gap — стандартный рецепт для кнопок со значками: элементы выстраиваются по вертикальному центру и между ними всегда одинаковый отступ.

7. Grid: линии, колонки и ряды

Grid включается свойством display: grid, а дальше описываются колонки и ряды: grid-template-columns и grid-template-rows. Каждая колонка или ряд задаётся шириной или высотой соответствующей дорожки.

.layout {
  display: grid;
  grid-template-columns: 200px 1fr 200px;  /* три колонки */
  grid-template-rows: 80px 1fr;            /* шапка и контент */
  gap: 16px;
}

Единица fr (fraction) — это доля свободного места. Три колонки 1fr 2fr 1fr означают: одну часть — левой боковой, две части — контенту, одну — правой. Остальные длины (px, %, auto) фиксированы, и fr делит остаток.

ЕдиницаПоведение
pxжёсткий размер, не зависит от ширины контейнера
% / autoадаптивный размер относительно контейнера
frдоля свободного пространства после других колонок
minmax()диапазон: от минимума до максимума
/* длинная колонка содержимого и две боковые */
.page {
  display: grid;
  grid-template-columns: 240px 1fr 240px;
  gap: 20px;
}
Свойство gap в grid работает по обоим осям сразу: gap: 16px — и колонки, и ряды отступают друг от друга одинаково.

8. Grid: repeat, minmax, автоматика

Писать десять одинаковых колонок вручную не нужно — есть функция repeat(). А для сеток с неизвестным числом элементов — два ключевых слова: auto-fill и auto-fit.

/* три равные колонки */
grid-template-columns: repeat(3, 1fr);

/* галерея: сколько влезет колонок от 200px, но не уже 1fr */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
Попробуй в примере заменить auto-fit на auto-fill — увидишь, как в конце ряда появятся «пустые» колонки, а карточки не растянутся на всю ширину.

9. Grid: размещение по линиям и областям

Каждая колонка и ряд сетки ограничены линиями — они нумеруются с 1. Элемент можно разместить, указав начальную и конечную линию (направления grid-column-start/grid-column-end и аналогичные для рядов).

/* элемент занимает колонки с 1-й по 3-ю линию (две колонки) */
.banner {
  grid-column-start: 1;
  grid-column-end: 3;
}
/* то же самое одной строкой: */
.banner { grid-column: 1 / 3; }
/* растянуться на всю ширину: */
.banner { grid-column: 1 / -1; }

Но самый читаемый способ собрать каркас страницы — именованные области через grid-template-areas. Каждая строка значения описывает один ряд сетки, каждое слово — область из колонок.

/* каркас страницы: header/sidebar/main/footer */
.page {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 220px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
  gap: 16px;
}
.page-header { grid-area: header; }
.page-sidebar { grid-area: sidebar; }
.page-main { grid-area: main; }
.page-footer { grid-area: footer; }
<div class="page">
  <header class="page-header">Шапка</header>
  <aside class="page-sidebar">Меню</aside>
  <main class="page-main">Контент</main>
  <footer class="page-footer">Подвал</footer>
</div>
Точка . в grid-template-areas означает пустую ячейку. Области должны образовывать прямоугольники без дырок — «буква Г» или две области по диагонали недопустимы, браузер проигнорирует объявление.

10. Grid: выравнивание внутри ячеек

Когда элемент размещён в ячейке, можно управлять его положением внутри неё. Свойства justify-items (горизонталь) и align-items (вертикаль) на контейнере задают выравнивание для всех ячеек сразу, а justify-self и align-self — для отдельного элемента.

.board {
  display: grid;
  grid-template-columns: repeat(3, 120px);
  grid-template-rows: repeat(2, 90px);
  /* по умолчанию ячейка растягивает элемент — stretch */
  justify-items: stretch;
  align-items: stretch;
}
.pin {
  align-self: center;   /* только этот элемент — по центру по вертикали */
  justify-self: center; /* и по центру по горизонтали */
}

Классический приём — центрирование элемента по обеим осям внутри grid-ячейки:

.cell {
  display: grid;
  place-items: center;  /* центр по горизонтали и вертикали */
  min-height: 200px;
}
place-items — сокращение сразу для align-items и justify-items. А в flexbox центрирование по обеим осям делается парой justify-content: center + align-items: center.

11. Вложенность: grid-страница с flex-панелями

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

<div class="page">
  <header class="page-header">Логотип и меню</header>
  <aside class="page-sidebar">Категории</aside>
  <main class="page-main">
    <h2>Новости</h2>
    <div class="cards">
      <article class="card">Новость 1</article>
      <article class="card">Новость 2</article>
      <article class="card">Новость 3</article>
      <article class="card">Новость 4</article>
    </div>
  </main>
  <footer class="page-footer">Подвал</footer>
</div>
.page {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 220px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
  gap: 16px;
}
.page-header  { grid-area: header; }
.page-sidebar { grid-area: sidebar; }
.page-main    { grid-area: main; }
.page-footer  { grid-area: footer; }

.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.card {
  flex: 1 1 240px;   /* карточки равной ширины, не уже 240px */
  padding: 16px;
  border-radius: 10px;
  background: #f1f5f9;
}
Асимметричные блоки внутри ячейки (например, форма с подписью и полем) — снова flexbox: display: flex на ячейке и flex-direction: column для вертикального ряда. Grid — каркас сверху, flex — панели внутри — это и есть типовой паттерн вёрстки.

12. Адаптив без медиазапросов

Связка repeat(auto-fit, minmax(...)) решает большую часть адаптивных задач без единого медиазапроса: сколько колонок помещается при текущей ширине, столько и рисуется — на телефоне одна, на десктопе пять.

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

Для шрифтов, не выпадающих из сетки, подходит функция clamp(): она задаёт минимум, желаемый размер и максимум. Текст плавно растёт вместе со страницей.

.title {
  /* от 1.2rem до 2.5rem, в идеале 5vw — доля ширины экрана */
  font-size: clamp(1.2rem, 5vw, 2.5rem);
}

Когда медиазапросы всё же нужны:

@media (max-width: 720px) {
  .page {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "main"
      "footer";
  }
  .page-sidebar { display: none; }  /* боковое меню прячем на телефоне */
}
Типовая стратегия: grid с auto-fit + minmax держит целые сетки резиновыми сами по себе, а медиазапросы резервируются только для перестроения каркаса страницы.

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

Путаница justify и align. justify-* всегда работает вдоль главной оси (в flex) или по горизонтали (в grid), align-* — вдоль поперечной оси или по вертикали. Начинаешь менять одно место — ничего не происходит — значит, ты выравниваешь не ту ось.
Flex на body вместо wrapper. Стили на body могут конфликтовать со стилями браузера и плагинов. Для раскладки страницы выделяй обёртку-контейнер, а body оставляй нейтральным.
margin вместо gap. Маргины на дочерних элементах снова заставляют считать «отступ у первого» и «отступ у последнего». Свойство gap делает это автоматически в flex и grid.
Фиксированные высоты. height: 100px на содержимом мстит при длинном тексте: текст переполняет блок и лезет поверх соседнего. Задавай min-height вместо жёсткой высоты, а для отсечения лишнего используй перенос и обрезку осознанно.
Забытый min-width: 0. Длинное слово или минимальная ширина контента может разорвать flex- и grid-дорожку. Добавь min-width: 0 на элемент, чтобы он мог сжиматься меньше содержимого.
Вёрстка каркаса на flex «в лоб». Рядок из шапки, сайдбара, контента и подвала на «одном большом flex» собирается через хаки с фиксированными ширинами. Это снова «табличная» вёрстка на новый лад — для каркаса всегда бери grid.

14. Чек-лист перед сдачей вёрстки

Пройдись по списку перед тем, как отдать макет в работу. Каждый пункт — отдельная проверка в DevTools и на живой странице.

Быстрая проверка: уменьшай окно браузера от максимума до минимума без DevTools. Если ломается только после перестроения каркаса — это ожидаемо; если сетка «сыпется» при любом движении — вернись к пункту про minmax и auto-fit.

Что дальше

Ты освоил обе системы раскладки: flexbox для панелей и grid для страниц, гибкость элементов, области и адаптив. Закрепи материал в практике: собери собственный лендинг по Практике: лендинг. Дальше по курсу — движение, жизнь и реакция интерфейса в CSS-анимациях, а фундамент, на который всё это ложится, — в основном курсе CSS.

← Вернуться к курсам