Современный CSS для простых адаптивных макетов
Создание адаптивных макетов раньше означало бесконечные медиазапросы, очистку float и хрупкие вычисления в процентах. Приходилось писать десяток контрольных точек только для того, чтобы карточка не вылезала за границы на планшетах. Современный CSS изменил это. Такие функции, как container queries, clamp() и CSS grid, позволяют создавать макеты, которые адаптируются к своему контексту — а не только к вьюпорту — с гораздо меньшим объёмом кода.
Почему традиционный адаптивный дизайн кажется сломанным
Классический подход опирается на контрольные точки по вьюпорту. Вы проверяете ширину экрана и переопределяете стили для каждого диапазона. Это работает для макета страницы в целом, но разваливается для переиспользуемых компонентов. Карточка в боковой панели может быть шириной 300px, тогда как та же карточка в основной колонке — 800px. Медиазапросы по вьюпорту не видят разницы — они знают только размер экрана.
Float и хаки с clearfix добавляли ещё один слой сложности. Даже с flexbox разработчики часто писали избыточные правила для обработки крайних случаев. Результат: раздутый CSS, непредсказуемое поведение и головная боль при поддержке.
Container queries: адаптация к родителю, а не к вьюпорту
Container queries — самый большой сдвиг в адаптивном дизайне со времён медиазапросов. Вместо вопроса «насколько широк экран?» вы спрашиваете «насколько широк мой контейнер?». Это делает компоненты по-настоящему переиспользуемыми.
Чтобы использовать их, определите контекст containment через container-type, а затем напишите правила @container:
.card-wrapper {
container-type: inline-size;
}
.card {
display: grid;
gap: 1rem;
}
@container (min-width: 400px) {
.card {
grid-template-columns: 150px 1fr;
}
}
Теперь карточка переключается на горизонтальную раскладку, когда её контейнер не менее 400px в ширину, независимо от вьюпорта. Поместите её в узкую боковую панель — она сложится вертикально; поместите в широкую основную колонку — она станет горизонтальной. Никаких дополнительных классов, никакого JavaScript.
Когда использовать container queries, а когда медиазапросы
- Container queries: для компонентов, которые появляются в разных контекстах (карточки, виджеты, блоки навигации).
- Медиазапросы: для изменений макета страницы (общая сетка, шапка/подвал, стили для печати).
Гибкие размеры с clamp() и min()/max()
Фиксированные контрольные точки создают скачки. clamp() позволяет задать минимум, предпочтительное значение и максимум в одной строке:
h1 {
font-size: clamp(1.5rem, 5vw, 3rem);
}
Заголовок плавно масштабируется вместе с вьюпортом, никогда не меньше 1.5rem и не больше 3rem. Медиазапросы не нужны. Тот же приём можно применять для padding, margin и даже отступов сетки.
min() и max() не менее полезны. Например, width: min(100% - 2rem, 1200px) создаёт центрированный контейнер, который никогда не касается краёв на маленьких экранах.
CSS Grid: внутренне адаптивные макеты без контрольных точек
CSS grid предлагает две мощные функции для адаптивного дизайна: auto-fit и minmax(). Вместе они создают адаптивную сетку, которая переносится автоматически:
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
Это единственное правило создаёт столько колонок, сколько помещается, каждая шириной не менее 250px. На телефоне получится одна колонка; на десктопе — четыре или больше. Никаких медиазапросов, никакого JavaScript.
Для большего контроля grid-template-areas позволяет задавать именованные области и перестраивать их на разных контрольных точках минимальным кодом.
Subgrid для выравнивания вложенных элементов
Subgrid решает давнюю проблему: выравнивание дочерних элементов между разными элементами сетки. Если у вас есть ряд карточек с заголовками, содержимым и подвалами, вы хотите, чтобы заголовки выстраивались в линию. Subgrid позволяет дочерней сетке наследовать дорожки родителя:
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3;
}
Теперь все карточки разделяют одинаковую высоту строк, сохраняя выравнивание содержимого без фиксированных высот и JavaScript.
Aspect-ratio: больше никаких хаков с padding
До aspect-ratio для поддержания блока 16:9 требовался трюк с padding-bottom. Теперь это одно свойство:
.video-thumbnail {
aspect-ratio: 16 / 9;
width: 100%;
object-fit: cover;
}
Это работает для изображений, видео и любого контейнера. Особенно удобно для адаптивных сеток медиа.
Логические свойства для интернационализации
Логические свойства, такие как margin-inline, padding-block и inset-inline-start, заменяют физические направления (left, right, top, bottom). Они автоматически адаптируются к режимам письма, поэтому ваш макет работает в RTL-языках без дополнительного CSS. Например, margin-inline: auto центрирует блок по горизонтали как в LTR, так и в RTL контекстах.
Сравнение: старые и современные приёмы
| Задача | Старый подход | Современный CSS |
|---|---|---|
| Адаптивная раскладка карточек | Медиазапросы + float | Container queries + grid |
| Гибкая типографика | Несколько контрольных точек для font-size | clamp() |
| Автоматически переносящаяся сетка | Flexbox с flex-basis в процентах | repeat(auto-fit, minmax()) |
| Фиксированное соотношение сторон | Хак с padding-bottom | aspect-ratio |
| Поддержка RTL | Отдельные таблицы стилей или переопределения direction | Логические свойства |
Собираем всё вместе: адаптивный компонент-карточка
Давайте создадим карточку, которая адаптируется к своему контейнеру, использует гибкие отступы и сохраняет соотношение сторон медиа:
.card-container {
container-type: inline-size;
}
.card {
display: grid;
gap: clamp(1rem, 2vw, 1.5rem);
padding: clamp(1rem, 3vw, 2rem);
border-radius: 8px;
background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.card img {
aspect-ratio: 16 / 9;
object-fit: cover;
width: 100%;
border-radius: 4px;
}
@container (min-width: 500px) {
.card {
grid-template-columns: 200px 1fr;
align-items: center;
}
}
Этот компонент работает в любом контексте — боковая панель, основное содержимое или модальное окно — без единого медиазапроса.
Поддержка браузеров и запасные варианты
Container queries поддерживаются во всех современных браузерах (Chrome 105+, Firefox 110+, Safari 16+). clamp(), grid и aspect-ratio имеют ещё более широкую поддержку. Для старых браузеров можно предусмотреть запасные варианты через @supports:
@supports not (container-type: inline-size) {
.card {
display: flex;
flex-wrap: wrap;
}
}
На практике большинство проектов могут внедрить эти функции уже сегодня с минимальным риском.
FAQ
Что такое container queries и чем они отличаются от медиазапросов?
Container queries позволяют стилизовать элементы в зависимости от размера их родительского контейнера, тогда как медиазапросы реагируют на размер вьюпорта. Container queries идеальны для переиспользуемых компонентов, которые появляются в разных контекстах макета.
Можно ли использовать clamp() для адаптивных отступов?
Да. clamp() работает с любым значением длины, включая padding, margin и gap. Он обеспечивает плавное масштабирование без контрольных точек, что делает его идеальным для адаптивных систем отступов.
Полностью ли современные функции CSS заменяют медиазапросы?
Нет. Медиазапросы по-прежнему полезны для изменений макета страницы и стилей печати. Современные функции, такие как container queries и clamp(), дополняют их, снижая потребность во множестве контрольных точек, но не устраняя их полностью.
Готовы протестировать свой адаптивный CSS? Используйте конвертер HTML в изображение, чтобы быстро делать скриншоты ваших макетов при разных размерах и проверять, как они адаптируются.