Кратко
СкопированоДиректива @container включает «контейнерные запросы» — условные правила, которые зависят от размеров и стилей ближайшего контейнера, а не от размеров вьюпорта. Это делает компоненты по‑настоящему адаптивными и независимыми от общего макета.
Пример
Скопировано
<div class="cards" aria-label="Список карточек"> <article class="card">Карточка 1</article> <article class="card">Карточка 2</article> <article class="card">Карточка 3</article> <article class="card">Карточка 4</article> <article class="card">Карточка 5</article></div>
<div class="cards" aria-label="Список карточек">
<article class="card">Карточка 1</article>
<article class="card">Карточка 2</article>
<article class="card">Карточка 3</article>
<article class="card">Карточка 4</article>
<article class="card">Карточка 5</article>
</div>
/* Объявляем контейнер: измеряем его inline‑ось (ширину в LTR/RTL) */.cards { container-type: inline-size; display: grid; gap: 12px; grid-template-columns: repeat(3, 1fr);}/* Когда контейнер сужается, меняем компоновку — компонент адаптируется сам по себе*/@container (max-width: 600px) { .cards { grid-template-columns: repeat(2, 1fr); }}@container (max-width: 380px) { .cards { grid-template-columns: 1fr; }}
/* Объявляем контейнер: измеряем его inline‑ось (ширину в LTR/RTL) */
.cards {
container-type: inline-size;
display: grid;
gap: 12px;
grid-template-columns: repeat(3, 1fr);
}
/*
Когда контейнер сужается, меняем компоновку —
компонент адаптируется сам по себе
*/
@container (max-width: 600px) {
.cards { grid-template-columns: repeat(2, 1fr); }
}
@container (max-width: 380px) {
.cards { grid-template-columns: 1fr; }
}
Как пишется
СкопированоКонтейнерный запрос срабатывает только в пределах контейнера. Чтобы он заработал, нужно:
-
Объявить контейнер на элементе‑родителе компонентов: задать ему
container(измеряет только ширину) или- type : inline - size container(измеряет и ширину, и высоту).- type : size -
По желанию дать контейнеру имя и ссылаться на него в
@container:
.wrapper { container-name: layout; container-type: inline-size;}@container layout (min-width: 700px) { /* правила для компонентов внутри .wrapper */}
.wrapper {
container-name: layout;
container-type: inline-size;
}
@container layout (min-width: 700px) {
/* правила для компонентов внутри .wrapper */
}
- Написать условия как в
@media, но изменять именно контейнер:
/* Размерные запросы */@container (min-width: 480px) { /* ... */ }@container (width > 30rem) { /* диапазонный синтаксис */ }/* Логические операторы */@container (min-width: 480px) and (max-width: 768px) { /* ... */ }@container (width < 400px) or (height < 300px) { /* ... */ }@container not (width > 800px) { /* ... */ }/* Стилевые запросы по вычисленным стилям */@container style(--ui: compact) { /* ... */ }@container style(--number > 4) and style(--theme: dark) { /* ... */ }/* Имя контейнера + условие */@container sidebar (width > 400px) { /* ... */ }/* Только имя — применяется ко всем контейнерам с этим именем */@container sidebar { /* ... */ }/* Имя + несколько условий через запятую (ИЛИ) */@container card (width > 400px), style(--featured: true) { /* ... */ }
/* Размерные запросы */
@container (min-width: 480px) { /* ... */ }
@container (width > 30rem) { /* диапазонный синтаксис */ }
/* Логические операторы */
@container (min-width: 480px) and (max-width: 768px) { /* ... */ }
@container (width < 400px) or (height < 300px) { /* ... */ }
@container not (width > 800px) { /* ... */ }
/* Стилевые запросы по вычисленным стилям */
@container style(--ui: compact) { /* ... */ }
@container style(--number > 4) and style(--theme: dark) { /* ... */ }
/* Имя контейнера + условие */
@container sidebar (width > 400px) { /* ... */ }
/* Только имя — применяется ко всем контейнерам с этим именем */
@container sidebar { /* ... */ }
/* Имя + несколько условий через запятую (ИЛИ) */
@container card (width > 400px), style(--featured: true) { /* ... */ }
Поддерживаются типы контейнеров:
inline— учитывает только ширину контейнера;- size size— учитывает и ширину, и высоту;normal— отключает контейнер.
Вложенные контейнеры
СкопированоМожно вкладывать @container друг в друга, чтобы комбинировать условия:
@container sidebar (width > 400px) { .card { font-size: 1.2rem; } @container (width > 700px) { .card { /* сработает, если sidebar > 400px И его родитель > 700px */ font-size: 1.5rem; } }}
@container sidebar (width > 400px) {
.card {
font-size: 1.2rem;
}
@container (width > 700px) {
.card {
/* сработает, если sidebar > 400px И его родитель > 700px */
font-size: 1.5rem;
}
}
}
Стилевые запросы style()
СкопированоКонтейнерные запросы умеют проверять не только размеры, но и значения CSS-свойств контейнера:
/* Булева форма — проверяет, что свойство отличается от initial */@container style(--theme: dark) { .card { color: #fff; background: #1a1a1a; }}@container style(--accent-color: blue) and style(--padding: large) { .card { padding: 2rem; border-color: blue; }}@container style(--number > 4) { .card { /* сработает, если --number больше 4 */ }}@container not style(--responsive: true) { .card { /* если responsive не true */ }}/* Диапазонный синтаксис для чисел */@container style(0 < --columns < 6) { .grid { grid-template-columns: repeat(var(--columns), 1fr); }}
/* Булева форма — проверяет, что свойство отличается от initial */
@container style(--theme: dark) {
.card {
color: #fff;
background: #1a1a1a;
}
}
@container style(--accent-color: blue) and style(--padding: large) {
.card {
padding: 2rem;
border-color: blue;
}
}
@container style(--number > 4) {
.card { /* сработает, если --number больше 4 */ }
}
@container not style(--responsive: true) {
.card { /* если responsive не true */ }
}
/* Диапазонный синтаксис для чисел */
@container style(0 < --columns < 6) {
.grid { grid-template-columns: repeat(var(--columns), 1fr); }
}
Важно: style смотрит на итоговые значения стилей. Если свойства у контейнера нет, запрос вернёт false.
Как понять
Скопировано@container решает классическую проблему адаптивности компонентов: ваш виджет может жить в сайдбаре и в контентной колонке, а меняться он должен по ширине своего родителя, а не окна. Теперь брейкпоинты описываются около компонента и работают в любом контексте вёрстки.
Контейнерные запросы также умеют работать с:
scroll— проверяют состояние прокрутки: прилип ли элемент, прокручен ли контейнер;- state ( ) anchored— проверяют, какое запасное положение активно у элемента с Anchor Positioning.( )
Эти возможности пока экспериментальные, но уже доступны в некоторых браузерах под флагами.
Подсказки
Скопировано💡 Всегда объявляйте контейнер на ближайшем родителе компонента (container). Без этого @container не сработает.
💡 Используйте имена контейнеров (container), когда на странице несколько контейнеров и правила не должны пересекаться.
💡 Храните брейкпоинты рядом с компонентом. Так проще сопровождать дизайн‑систему.
💡 Не плодите лишних контейнеров: слишком глубокая вложенность замедляет отрисовку.
- Chrome 111, поддерживается
- Edge 111, поддерживается
- Firefox 110, поддерживается
- Safari 17, поддерживается