Как сделать адаптивную вёрстку — CSS Grid, Flexbox, clamp()
Адаптивная вёрстка прошла долгий путь: от фиксированных табличных макетов в 2000-х до резиновых сеток на CSS Grid в 2026. Если раньше верстальщик держал в голове три разрешения (320px, 768px, 1024px) и писал медиа-запросы под каждое, то сегодня CSS позволяет создавать макеты, которые подстраиваются автоматически. Разберём три главных инструмента: Flexbox, CSS Grid и математические функции, а также новейшие технологии вроде Container Queries.
Краткая история: от таблиц до Container Queries
В начале 2000-х вёрстка делалась на HTML-таблицах. Ширина задавалась в пикселях. Если экран был уже — появлялся горизонтальный скролл. В середине 2000-х появились float-макеты с фиксированной шириной. Затем — резиновая вёрстка с процентами. В 2012-2015 стали популярны медиа-запросы и mobile-first. В 2017-2020 CSS получил Flexbox и Grid — настоящие инструменты для раскладки. В 2023-2026 добавились Container Queries и каскадные слои (@layer), которые окончательно изменили подход к адаптиву. Сегодня грамотный верстальщик пишет минимум медиа-запросов, полагаясь на встроенные возможности CSS.
1. Flexbox — для одномерных макетов
Flexbox (Flexible Box Layout) предназначен для раскладки элементов в одном направлении — по строке или колонке. Это идеальный инструмент для шапок, навигации, карточек, центрирования.
Свойства контейнера
display: flex — включает flex-контекст. Все дочерние элементы становятся flex-элементами.
flex-direction — задаёт направление главной оси:
.container { flex-direction: row; } /* слева направо (по умолчанию) */
.container { flex-direction: column; } /* сверху вниз */
.container { flex-direction: row-reverse; } /* справа налево */
justify-content — выравнивание по главной оси:
.container { justify-content: flex-start; } /* прижаты к началу */
.container { justify-content: center; } /* по центру */
.container { justify-content: space-between; } /* равномерно, крайние к краям */
.container { justify-content: space-evenly; } /* строго равные отступы */
align-items — выравнивание по поперечной оси:
.container { align-items: stretch; } /* растянуть на всю высоту (по умолчанию) */
.container { align-items: center; } /* по центру - самое частое */
.container { align-items: flex-start; } /* прижать к верху */
flex-wrap — перенос элементов на новую строку:
.container { flex-wrap: nowrap; } /* не переносить (по умолчанию) */
.container { flex-wrap: wrap; } /* переносить, если не влезают */
Свойства flex-элементов
flex-grow — коэффициент растягивания (0 — не растягивать, 1 — растянуть пропорционально).
flex-shrink — коэффициент сжатия (1 — можно сжимать, 0 — нельзя сжимать).
flex-basis — начальный размер элемента до растяжения/сжатия.
Короткая запись — flex: grow shrink basis:
.flex-1 { flex: 1; } /* flex: 1 1 0 — растянуть, занимает всё пространство */
.flex-auto { flex: 1 1 auto; } /* растянуть, но учитывать размер контента */
.flex-none { flex: 0 0 auto; } /* не растягивать, исходный размер */
.flex-300 { flex: 1 1 300px; } /* минимум 300px, может расти */
Реальный пример: шапка сайта на Flexbox
.header {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 1rem;
padding: 1rem 2rem;
}
.logo { flex: 0 0 auto; }
.nav { display: flex; gap: 2rem; }
.cta { flex: 0 0 auto; }
На десктопе логотип слева, навигация по центру, кнопка справа. На мобильном навигация переносится на новую строку. Ни одного медиа-запроса.
Реальный пример: карточки услуг
.services {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.service-card {
flex: 1 1 280px;
padding: 1.5rem;
border: 1px solid var(--border);
border-radius: 12px;
}
Карточки занимают минимум 280px. На экране 1200px — 4 карточки. На 600px — 2. На 300px — 1. Идеально адаптивно.
2. CSS Grid — для двумерных макетов
CSS Grid управляет строками и колонками одновременно. Это полноценная двумерная система в отличие от одномерного Flexbox.
Основные свойства Grid
grid-template-columns и grid-template-rows — определяют количество и размер колонок/строк:
.grid {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* три колонки: средняя в 2 раза шире */
grid-template-rows: auto 1fr auto; /* шапка, контент, подвал */
gap: 1.5rem;
}
repeat() — повторяет колонки:
grid-template-columns: repeat(3, 1fr); /* три равные колонки */ grid-template-columns: repeat(12, 1fr); /* 12-колоночная сетка */
auto-fill vs auto-fit:
/* auto-fill — создаёт пустые колонки */ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* auto-fit — схлопывает пустые колонки */ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
auto-fill оставляет пустые треки, если элементов меньше, чем может поместиться. auto-fit схлопывает их — элементы растягиваются. Для карточек товаров обычно нужен auto-fit.
minmax() — задаёт минимальный и максимальный размер колонки:
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); /* каждая колонка минимум 280px, максимум 1fr */
grid-area и именованные области
.layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
grid-template-columns: 250px 1fr 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
/* На мобильных */
@media (max-width: 768px) {
.layout {
grid-template-areas:
"header"
"content"
"sidebar"
"footer";
grid-template-columns: 1fr;
}
}
Этот приём невероятно удобен: вы описываете макет словами, а медиа-запрос просто переопределяет расположение областей.
Реальный пример: галерея на Grid
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.5rem;
}
.gallery img {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 8px;
}
.gallery img:first-child {
grid-column: span 2;
grid-row: span 2;
height: 412px;
}
Первое изображение занимает 2 колонки и 2 строки — оно крупнее. Остальные — равномерная сетка. Выглядит как hand-crafted сетка в Pinterest, но делается в 10 строк CSS.
Flexbox vs CSS Grid: когда что использовать
| Сценарий | Flexbox | Grid |
|---|---|---|
| Шапка сайта (лого + навигация) | ✅ | ❌ |
| Центрирование блока по вертикали и горизонтали | ✅ | ❌ |
| Карточки с переносом строк | ✅ | ✅ |
| Сложная сетка с overlapping | ❌ | ✅ |
| Раскладка «шапка-контент-подвал» на весь экран | ❌ | ✅ |
| Галерея с элементами разного размера | ❌ | ✅ |
Правило: если макет одномерный (строка или колонка) — Flexbox. Если двумерный (строки и колонки одновременно) — Grid. Умение выбирать правильный инструмент — признак опытного верстальщика.
3. clamp(), min(), max() — математика адаптива
Современный CSS включает три функции для размеров как диапазонов, без медиа-запросов:
clamp(MIN, PREFERRED, MAX) — размер в диапазоне. Если preferred меньше MIN — берётся MIN. Больше MAX — берётся MAX.
/* Размер заголовка: от 1.5rem до 3rem, плавно меняется */
h1 { font-size: clamp(1.5rem, 4vw, 3rem); }
/* Отступы контейнера */
.container { padding: clamp(1rem, 5vw, 3rem); }
/* Ширина колонки с текстом (читаемость) */
article { width: clamp(300px, 65ch, 800px); }
/* Высота hero-секции */
.hero { min-height: clamp(300px, 50vh, 700px); }
min() — выбирает наименьшее значение:
.container {
width: min(90%, 1200px); /* 90% от родителя, но не больше 1200px */
}
max() — выбирает наибольшее значение:
.sidebar {
width: max(250px, 20%); /* минимум 250px, но и 20% от родителя */
}
4. CSS Container Queries — новая эра адаптива
Container Queries (поддержка в Chrome 105+, Safari 16+, Firefox 110+) позволяют компоненту подстраиваться под размер своего контейнера, а не под размер окна. Это решает проблему, когда один и тот же компонент используется в разных контекстах.
/* Шаг 1: определить контейнер */
.card-container {
container-type: inline-size;
container-name: card;
}
/* Шаг 2: стили внутри контейнера */
@container card (max-width: 400px) {
.card { flex-direction: column; }
.card-image { width: 100%; }
}
@container card (min-width: 401px) {
.card { flex-direction: row; }
.card-image { width: 200px; }
}
В 2026 Container Queries стабильно поддерживаются всеми современными браузерами. Используйте их как прогрессивное улучшение.
5. Когда медиа-запросы всё-таки нужны
Медиа-запросы полностью не исчезли. Они нужны для:
— Изменения порядка блоков (sidebar под контент на мобильных)
— Скрытия/показа блоков (сложная декорация убирается на телефоне)
— Навигации (меню-гамбургер на мобильных)
— Коррекции отступов между секциями
— Тёмной темы (prefers-color-scheme)
— Поведения пользователя (prefers-reduced-motion)
/* mobile-first: базовая верстка для мобильных */
.nav { display: none; }
.hamburger { display: block; }
/* desktop */
@media (min-width: 1024px) {
.nav { display: flex; gap: 2rem; }
.hamburger { display: none; }
}
6. mobile-first vs desktop-first
Mobile-first — базовые стили для мобильных, затем min-width для больших экранов. Рекомендуемый подход: фокус на главном, прогрессивное улучшение.
Desktop-first — стили для десктопа, max-width для меньших экранов. Работает, но мобильная версия выглядит как «урезанная десктопная».
В 2026 году мобильный трафик — 60-70% всего интернет-трафика. Начинайте с мобильной версии.
7. Инструменты тестирования адаптива
Chrome DevTools. F12 → иконка телефона → переключайтесь между устройствами, эмулируйте touch.
Responsively App. Бесплатно. Показывает сайт на 10+ разрешениях одновременно.
BrowserStack. Платный сервис для реальных устройств. Бесплатный период — 30 минут.
LambdaTest. Аналог BrowserStack с бесплатным тарифом.
Современная вёрстка — это flex/grid + clamp() + auto-fill, дополненные Container Queries для вложенных компонентов. Медиа-запросы — только для исключений. Чем меньше медиа-запросов — тем чище и поддерживаемее код.