$ sudo teach IT
Урок 4.4 — Flexbox

Урок 4.4: Flexbox

Модуль 4 — Основы CSS

display: flex — контейнер становится «умным»

Раньше, чтобы расположить элементы в ряд, разработчики мучились с float, inline-block и магией отрицательных margin'ов. Это было больно. Потом пришёл Flexbox — и всё стало просто.

Flexbox (сокращение от Flexible Box Layout) — это CSS-модуль, который делает раскладку элементов предсказуемой и гибкой. Всё, что нужно — сказать родителю display: flex, и его дети волшебным образом выстраиваются в аккуратный ряд.

.container {
  display: flex;
}

Вот и всё. Одна строчка — и дочерние элементы перестают быть просто блоками друг под другом. Они становятся flex-элементами и слушаются своего родителя-контейнера.

1
2
3
4
display: flex — элементы встали в ряд

Без flex'а каждый <div> был бы на своей строке. С flex'ом они дружно стоят плечом к плечу. Но это только начало. Настоящая сила flexbox раскрывается, когда мы начинаем управлять тем, как именно они стоят.

Flexbox работает в двух измерениях, но по-настоящему он крут в одном — вдоль главной оси (main axis) и поперечной оси (cross axis). Главная ось — это направление, в котором располагаются элементы. По умолчанию — слева направо (как строки в тексте).

Давай посмотрим на схему:

     ──────── главная ось (main axis) ────────→
    ┌────────────────────────────────────────┐
    │  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐│
    │  │  1   │  │  2   │  │  3   │  │  4   ││
 ↑  │  └──────┘  └──────┘  └──────┘  └──────┘│
 │  └────────────────────────────────────────┘
поперечная ось (cross axis)

Пока просто запомни: main axis — это куда смотрят элементы (по умолчанию вправо), а cross axis — перпендикулярно им (по умолчанию вниз). Все свойства flexbox крутятся вокруг этих двух осей.

💡 Совет: Flexbox решает 90% задач с раскладкой. Для сложных двумерных сеток есть Grid, но для рядов, колонок и центрирования flexbox — король.

flex-direction — направление

По умолчанию элементы выстраиваются в строку (слева направо). Но flexbox умеет и в колонку. За это отвечает свойство flex-direction.

.container {
  display: flex;
  flex-direction: row;        /* по умолчанию — в строку */
  flex-direction: row-reverse; /* строка задом наперёд */
  flex-direction: column;      /* в колонку сверху вниз */
  flex-direction: column-reverse; /* колонка снизу вверх */
}

Вот как выглядит разница между row и column:

flex-direction: row

1
2
3

flex-direction: column

1
2
3
flex-direction меняет главную ось

Когда ты меняешь flex-direction, главная ось поворачивается. При row элементы идут вправо (main axis — горизонталь). При column — вниз (main axis — вертикаль). Все остальные свойства flexbox, которые мы будем разбирать, работают относительно этой оси.

row-reverse и column-reverse делают то же самое, но в обратном порядке:

row-reverse

1
2
3

column-reverse

1
2
3
reverse — элементы идут в обратном порядке

Порядок меняется визуально, HTML остаётся тем же. Это удобно, когда нужно изменить порядок отображения без изменения разметки.

justify-content — выравнивание по главной оси

Это, пожалуй, самое часто используемое свойство flexbox. justify-content управляет тем, как элементы распределяются вдоль главной оси (то есть вправо вдоль строки или вниз вдоль колонки).

.container {
  display: flex;
  justify-content: flex-start;   /* прижаты к началу (по умолчанию) */
  justify-content: flex-end;     /* прижаты к концу */
  justify-content: center;       /* по центру */
  justify-content: space-between; /* первый в начале, последний в конце, остальные поровну */
  justify-content: space-around;  /* равные отступы вокруг каждого */
  justify-content: space-evenly;  /* строго равные отступы */
}

Смотри, как это выглядит на практике. Каждый пример — один и тот же контейнер с разным justify-content:

flex-start

1
2
3

flex-end

1
2
3

center — самый популярный

1
2
3

space-between

1
2
3

space-around

1
2
3

space-evenly

1
2
3

Обрати внимание на разницу между space-between и space-evenly. В space-between первый элемент прижат к левому краю, последний — к правому. В space-evenly отступы между всеми элементами (включая края) строго одинаковые. space-around — компромисс: отступы вокруг каждого элемента одинаковы, но по краям они в два раза меньше (потому что не складываются с соседними).

💡 Совет: justify-content: center — самый частый способ отцентрировать группу элементов по горизонтали. Но для центрирования одного элемента всё равно используй его — это проще, чем margin: auto.

align-items — выравнивание по поперечной оси

Если justify-content работает вдоль главной оси, то align-items — вдоль поперечной. Простыми словами: если элементы идут в ряд (row), align-items управляет их положением по вертикали.

.container {
  display: flex;
  align-items: stretch;    /* растянуть на всю высоту (по умолчанию) */
  align-items: flex-start; /* прижать к верху */
  align-items: flex-end;   /* прижать к низу */
  align-items: center;     /* отцентрировать по вертикали */
  align-items: baseline;   /* выровнять по базовой линии текста */
}

Посмотри на разницу. Здесь все контейнеры имеют высоту 120px, а элементы — разной высоты:

stretch

1
2
3

center — вертикальный центр

1
2
3

flex-end

1
2
3
align-items управляет вертикальным положением (при row)

Самое частое использование align-items: center — отцентрировать элемент по вертикали. Раньше для этого приходилось танцевать с бубном, а теперь — одна строка CSS.

.parent {
  display: flex;
  align-items: center;      /* по вертикали */
  justify-content: center;  /* по горизонтали */
}

/* Идеальное центрирование одной строкой! */

Вот как это выглядит:

Я по центру! 🎯

Всего два свойства — и элемент идеально отцентрирован и по вертикали, и по горизонтали. Внутри блока может быть что угодно: текст, картинка, форма. flexbox всё отцентрирует.

Это настолько распространённый паттерн, что его выделяют в отдельный класс:

.center {
  display: flex;
  align-items: center;
  justify-content: center;
}

Используй его для иконок в кружках, для центрирования модальных окон, для прелоадеров — везде, где нужно что-то разместить ровно посередине.

gap — расстояние между элементами

Раньше, чтобы сделать отступы между flex-элементами, использовали margin на каждом элементе. Это работало, но было муторно — нужно было убрать margin у последнего элемента, чтобы не было лишнего отступа. Потом появился gap, и всё стало проще.

.container {
  display: flex;
  gap: 20px;  /* расстояние между всеми элементами */
}

/* Можно задавать разные значения для строк и колонок */
gap: 16px 24px; /* row-gap column-gap */
row-gap: 16px;
column-gap: 24px;

gap добавляет отступы только между элементами. До и после первого/последнего элемента отступов нет. Это идеально для списков, меню, карточек.

gap: 8px

1
2
3
4
gap: 24px
1
2
3
4

Обрати внимание: во втором примере отступы между элементами 24px, но до левого и правого края отступа нет. gap не добавляет отступов по краям, только между элементами. Если нужны отступы по краям — используй padding на контейнере.

💡 Совет: Всегда используй gap вместо margin на flex-детях. Это чище, короче и не требует костылей для последнего элемента.

flex-wrap — перенос на новую строку

По умолчанию flex-элементы стараются поместиться в одну строку. Если они не влезают, они сжимаются (flexbox умеет уменьшать элементы). Но часто нужно, чтобы они переносились на следующую строку — как слова в тексте. Для этого есть flex-wrap.

.container {
  display: flex;
  flex-wrap: nowrap;    /* не переносить (по умолчанию) */
  flex-wrap: wrap;      /* переносить, если не влезают */
  flex-wrap: wrap-reverse; /* переносить в обратном порядке */
}

Посмотри, как работает wrap:

flex-wrap: nowrap — элементы сжимаются

Очень длинный текст, который не влезает
Тоже длинный текст
И ещё один

flex-wrap: wrap — перенос на новую строку

Элемент 1
Элемент 2
Элемент 3
Элемент 4
Элемент 5
Элемент 6
Элементы с flex-basis: 200px переносятся, когда не влезают

Обрати внимание: когда элементы переносятся, они создают несколько рядов. Каждый ряд работает как отдельный flex-контейнер. Flex-wrap особенно полезен для:

  • Сеток карточек (каталог товаров, галерея)
  • Тегов и категорий
  • Меню, где пункты могут не поместиться
  • Списков иконок с подписями

Вот пример сетки карточек с flex-wrap:

📱

Смартфон

49 990 ₽

💻

Ноутбук

89 990 ₽

🎧

Наушники

7 490 ₽

⌚

Часы

24 990 ₽

📷

Камера

55 000 ₽

🖨️

Принтер

12 990 ₽

Каждая карточка имеет фиксированную ширину 170px. Когда они не влезают в ряд, flex-wrap переносит их на следующую строку. И gap создаёт аккуратные отступы между ними. Всё это — без единого margin или float.

Практика: карточки товаров в ряд, центрирование блока

Давай соберём всё, что мы выучили, в один проект. Мы сверстаем секцию с товарами:

  • Карточки товаров в ряд
  • Центрирование содержимого
  • Отступы между карточками через gap
  • Перенос на новую строку, если не влезают

Вот полный код. Скопируй и открой в браузере:

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Каталог товаров</title>
<style>
  *, *::before, *::after {
    box-sizing: border-box;
  }
  body {
    font-family: 'Segoe UI', system-ui, sans-serif;
    background: #f5f5f5;
    margin: 0;
    padding: 40px 20px;
  }
  .section-title {
    text-align: center;
    font-size: 1.8em;
    color: #333;
    margin-bottom: 32px;
  }
  .product-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 24px;
    max-width: 900px;
    margin: 0 auto;
  }
  .product-card {
    background: #fff;
    border-radius: 14px;
    padding: 24px 20px;
    width: 240px;
    text-align: center;
    box-shadow: 0 2px 12px rgba(0,0,0,0.06);
    transition: transform 0.2s, box-shadow 0.2s;
  }
  .product-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 6px 20px rgba(0,0,0,0.1);
  }
  .product-icon {
    width: 80px;
    height: 80px;
    background: linear-gradient(135deg, #667eea, #764ba2);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2em;
    margin: 0 auto 16px;
  }
  .product-card h3 {
    margin: 0 0 6px;
    color: #333;
    font-size: 1.2em;
  }
  .product-desc {
    color: #777;
    font-size: 0.9em;
    margin: 0 0 14px;
    line-height: 1.5;
  }
  .product-price {
    font-size: 1.4em;
    font-weight: bold;
    color: #10b981;
    margin: 0;
  }
  .product-btn {
    display: inline-block;
    margin-top: 14px;
    padding: 10px 28px;
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: #fff;
    border-radius: 30px;
    text-decoration: none;
    font-size: 0.9em;
    transition: opacity 0.2s;
  }
  .product-btn:hover {
    opacity: 0.85;
  }
</style>
</head>
<body>
  <h1 class="section-title">📦 Наши товары</h1>
  <div class="product-grid">
    <div class="product-card">
      <div class="product-icon">📱</div>
      <h3>Смартфон</h3>
      <p class="product-desc">6.7" экран, 128GB памяти</p>
      <p class="product-price">49 990 ₽</p>
      <a href="#" class="product-btn">Купить</a>
    </div>
    <div class="product-card">
      <div class="product-icon">💻</div>
      <h3>Ноутбук</h3>
      <p class="product-desc">15.6", 16GB RAM, SSD 512GB</p>
      <p class="product-price">89 990 ₽</p>
      <a href="#" class="product-btn">Купить</a>
    </div>
    <div class="product-card">
      <div class="product-icon">🎧</div>
      <h3>Наушники</h3>
      <p class="product-desc">Беспроводные, ANC</p>
      <p class="product-price">7 490 ₽</p>
      <a href="#" class="product-btn">Купить</a>
    </div>
    <div class="product-card">
      <div class="product-icon">⌚</div>
      <h3>Умные часы</h3>
      <p class="product-desc">GPS, пульсометр, вода</p>
      <p class="product-price">24 990 ₽</p>
      <a href="#" class="product-btn">Купить</a>
    </div>
    <div class="product-card">
      <div class="product-icon">📷</div>
      <h3>Камера</h3>
      <p class="product-desc">24MP, 4K видео</p>
      <p class="product-price">55 000 ₽</p>
      <a href="#" class="product-btn">Купить</a>
    </div>
    <div class="product-card">
      <div class="product-icon">🖨️</div>
      <h3>Принтер</h3>
      <p class="product-desc">Лазерный, двусторонняя печать</p>
      <p class="product-price">12 990 ₽</p>
      <a href="#" class="product-btn">Купить</a>
    </div>
  </div>
</body>
</html>

Давай разберём, что здесь использует flexbox:

  • .product-grid — display: flex с flex-wrap: wrap и gap: 24px. Это создаёт сетку, где карточки автоматически переносятся на новую строку.
  • justify-content: center — центрирует весь ряд карточек.
  • .product-icon — display: flex с align-items: center и justify-content: center. Иконка идеально отцентрирована в кружке.
  • .product-btn — display: inline-block (не flex, но тоже для inline-раскладки).

Обрати внимание: мы не использовали ни одного float, clearfix или display: inline-block с маржинами. Всё сделано чистым flexbox'ом.

А вот ещё один пример — центрирование любого содержимого. Это очень частый паттерн:

<div class="hero">
  <div class="hero-content">
    <h1>Добро пожаловать!</h1>
    <p>Мы рады видеть вас на нашем сайте</p>
    <a href="#" class="btn">Узнать больше</a>
  </div>
</div>

<style>
  .hero {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: #fff;
    text-align: center;
    padding: 20px;
  }
  .hero h1 {
    font-size: 3em;
    margin: 0 0 12px;
  }
  .hero p {
    font-size: 1.2em;
    opacity: 0.9;
    margin: 0 0 24px;
  }
  .btn {
    display: inline-block;
    padding: 14px 36px;
    background: #fff;
    color: #667eea;
    border-radius: 30px;
    text-decoration: none;
    font-weight: bold;
    transition: transform 0.2s;
  }
  .btn:hover {
    transform: scale(1.05);
  }
</style>

В этом примере .hero — flex-контейнер на всю высоту экрана (min-height: 100vh). align-items: center и justify-content: center центрируют дочерний .hero-content идеально посередине. Контент может быть любой высоты — он всегда будет по центру.

Давай подведём итог. Вот шпаргалка по flexbox:

/* FLEXBOX — ШПАРГАЛКА */

/* Родитель (контейнер) */
display: flex;
flex-direction: row | column;
flex-wrap: wrap | nowrap;
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
align-items: stretch | flex-start | flex-end | center | baseline;
gap: 16px;

/* Ребёнок (flex-элемент) */
flex: 1;                      /* растянуться на всё свободное место */
flex: 0 0 200px;              /* не сжиматься, не расти, ширина 200px */
align-self: center;           /* своё выравнивание (переопределяет align-items) */
order: 1;                     /* порядок (по умолчанию 0) */

Главное, что нужно запомнить:

  • display: flex включает flexbox на контейнере
  • Главная ось — flex-direction (row или column)
  • justify-content — вдоль главной оси
  • align-items — вдоль поперечной оси
  • gap — расстояние между элементами (удобно!)
  • flex-wrap: wrap — перенос на новую строку
  • Комбинация justify-content: center + align-items: center — идеальное центрирование

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

💡 Задание: Открой Codepen или локальный HTML-файл. Создай контейнер с 5 элементами. Поэкспериментируй с разными комбинациями flex-direction, justify-content и align-items. Попробуй добиться, чтобы элементы были в колонке, прижаты к правому краю и растянуты по ширине.
Урок 4.4 — Flexbox | Модуль 4: Основы CSS

Урок 4.4: Flexbox

9 вопросов