CSS Container Queries: где они уже работают
Контейнерные запросы (CSS Container Queries) — это инструмент, который ждали пятнадцать лет. Раньше адаптивная вёрстка строилась только на ширине viewport, и компонент в боковой панели и в основной области приходилось писать одинаково: либо подстраиваясь под огромный экран, либо под маленький. Контейнерные запросы дают компоненту реагировать на ширину своего родителя.
В 2026 году поддержка достаточно стабильна для прода. Я их использую в трёх живых проектах. Расскажу, что работает, что осторожно и какие сценарии действительно меняют код.
Базовый синтаксис
На контейнере включаем container-type:
.card-host {
container-type: inline-size;
container-name: card;
}inline-size — нас интересует ширина контейнера. Альтернатива — size (и ширина, и высота, но дорого по производительности и редко нужно).
Дальше внутри — медиа-подобный запрос:
.card {
display: block;
}
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 120px 1fr;
gap: 1rem;
}
}Если контейнер шире 400 пикселей — отрисуй карточку как двухколоночную; если уже — как обычный блок. Никакой связи с шириной браузера.
Сокращённый синтаксис
Если у тебя один контейнер на компонент — можно не давать ему имя:
.card-host { container-type: inline-size; }
@container (min-width: 400px) {
.card { display: grid; }
}Я именую только тогда, когда внутри есть вложенные контейнеры разных уровней.
Где это меняет жизнь
Карточки в гридах
Самый показательный пример. У нас в e-commerce есть карточка товара. На лендинге она в одной колонке (узкая), в каталоге — в трёх (средняя), в детальной — в одной полной (широкая). Раньше приходилось писать три варианта компонента или подстраиваться через :where-селекторы.
С контейнерными запросами один компонент сам решает: при 320px показывать обложку и заголовок, при 480px — добавить блок цены справа, при 720px — развернуть всё в горизонтальный layout с кнопкой «купить».
Сайдбары и виджеты
Виджет «связанные посты» в правой колонке узкий, в подвале — широкий. Один компонент — два разных layout. Я это использовала в портале новостей, и команда оценила: вёрстка стала ощутимо проще, дизайнер перестал слать варианты «для узкого случая».
Компоненты в админках
Таблицы, формы, диаграммы. На большом мониторе — широкая раскладка с боковой статистикой; на половинной ширине — стек. Без контейнерных запросов это решается JS-измерением, что ужасно для производительности.
Container query units
В дополнение к запросам появились новые единицы измерения, привязанные к размеру контейнера:
cqw— 1% ширины контейнера;cqh— 1% высоты;cqi— 1% inline-размера (логическая ширина);cqb— 1% block-размера;cqminиcqmax— минимум/максимум inline и block.
Применение: например, заголовок карточки занимает 8% от ширины контейнера, и адаптируется без медиа-запросов:
.card-title {
font-size: clamp(1rem, 4cqi, 1.5rem);
}Тут 4cqi — 4% от inline-размера контейнера. На узкой раскладке шрифт будет ближе к 1rem, на широкой — к 1.5rem, плавно. Без брейкпоинтов.
Style queries
В 2026 году в Chromium и Safari работают style queries — запросы по значению CSS-переменной контейнера. Это даёт интересные паттерны темизации:
.theme-host { --mode: dark; }
@container style(--mode: dark) {
.label { color: white; }
}В Firefox style queries пока в работе, не во всех версиях. Я бы для прод-проекта пока избегала зависимости от этой фичи.
Поддержка браузеров
Размерные контейнерные запросы (min-width, max-width) — стабильны в Chromium 105+, Safari 16+, Firefox 110+. На январь 2026 это покрывает почти весь актуальный трафик. Я в проектах перестала их полифилить около года назад.
Ширина и единицы cq* поддерживаются параллельно с запросами, нет смысла разделять.
Что осторожно
Контейнерные запросы создают новый «формирующий контекст» для содержимого. Это значит, что элементы с position: fixed внутри контейнера могут вести себя не так, как ты ожидаешь — фактически они становятся fixed-овыми относительно контейнера, а не viewport. Решение — выносить такие элементы выше по дереву.
Ещё одно: container-type: inline-size делает невозможным height: 100% у дочерних элементов в обычном режиме. Если внутри был трюк с заполнением высоты — переписывай через min-height или CSS Grid.
Производительность: для большинства случаев контейнерные запросы не дороже медиа-запросов. Но если ты применяешь container-type: size к огромному количеству элементов (тысячи), браузер начинает нагружаться. На больших сетках — переходи на inline-size, его дешевле обрабатывать.
Реальный пример карточки
Покажу полную карточку, которая адаптируется по контейнеру. Один компонент, три состояния:
.product-card {
container-type: inline-size;
container-name: card;
border-radius: 12px;
overflow: hidden;
background: #fff;
}
.product-card__inner {
display: grid;
gap: 0.75rem;
padding: 1rem;
}
.product-card__image { aspect-ratio: 4/3; }
.product-card__price { font-weight: 600; }
@container card (min-width: 360px) {
.product-card__inner {
grid-template-columns: 120px 1fr;
gap: 1rem;
}
}
@container card (min-width: 600px) {
.product-card__inner {
grid-template-columns: 200px 1fr auto;
align-items: center;
}
.product-card__cta { justify-self: end; }
}Один HTML, три раскладки. Никаких @media, никакого JS. Карточка работает одинаково в любом контексте — главное, чтобы родитель был контейнером.
Имена контейнеров и вложенность
Когда контейнеров несколько, удобно их именовать:
.layout { container: layout / inline-size; }
.sidebar { container: sidebar / inline-size; }
.card { container: card / inline-size; }
@container card (min-width: 400px) {
.card-title { font-size: 1.25rem; }
}
@container sidebar (min-width: 280px) {
.nav-list { gap: 0.5rem; }
}Запрос @container card ищет ближайшего предка с именем card, не путая со sidebar. На вложенных компонентах это спасает от случайных совпадений.
Когда не использовать
- Очень простые сайты с одной колонкой — там и медиа-запросов хватит.
- Layout, который зависит от ширины окна (хедер, футер) — здесь именно viewport.
- Анимации с трансформациями — не клади на контейнер, могут быть странные эффекты с трансформирующимся контекстом.
В сухом остатке
Container queries окончательно изменили подход к адаптивной вёрстке. Я больше не пишу один компонент для трёх контекстов и не «защищаюсь» от переноса. Компонент просто знает, в каком пространстве он живёт. Команды, которые перешли на этот стиль, отмечают: меньше CSS, чище код, быстрее правки. И главное — дизайнеры внезапно начали мыслить компонентами, а не страницами.