Перейти к содержимому

44. Container Queries (@container)

Иллюстрация к уроку

Container Queries позволяют стилизовать элементы исходя из размера их контейнера, а не из размера всего окна браузера. Это делает компоненты по-настоящему переиспользуемыми: один и тот же компонент автоматически адаптируется к любому месту на странице.

С медиа-запросами карточка реагирует на ширину экрана. Но что если она стоит в узком сайдбаре при широком экране? Медиа-запрос ничего не знает об этом.

Container Queries решают проблему: карточка реагирует на ширину своего контейнера.

/* Медиа-запрос — реагирует на экран */
@media (min-width: 700px) {
.card { font-size: 2em; }
}
/* Container query — реагирует на контейнер */
@container (width > 700px) {
.card { font-size: 2em; }
}

Сначала нужно сказать браузеру, что элемент является контейнером. Для этого используется свойство container-type:

.wrapper {
container-type: inline-size; /* следим за шириной */
}
ЗначениеЧто делает
inline-sizeСледит за шириной (горизонтальная ось). Самый частый случай.
sizeСледит за шириной и высотой одновременно.
normalКонтейнер для style queries, но не для size queries.

/* Стили по умолчанию */
.card {
display: block;
}
/* Когда контейнер шире 500px */
@container (width > 500px) {
.card {
display: flex;
gap: 1rem;
}
}

Синтаксис условий такой же, как в @media:

@container (min-width: 400px) { … } /* классика */
@container (width > 400px) { … } /* современный Range Syntax */
@container (400px < width < 800px) { … } /* диапазон */

Когда контейнеров несколько, нужно уточнить — к какому обращаемся. Имя задаётся через container-name:

.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.main-content {
container-type: inline-size;
container-name: main;
}
/* Реагирует только на контейнер с именем sidebar */
@container sidebar (width > 300px) {
.card { font-size: 0.9em; }
}
/* Реагирует только на контейнер с именем main */
@container main (width > 600px) {
.card { font-size: 1.4em; }
}

Шортхенд container объединяет имя и тип в одну строку:

/* container: <name> / <type> */
.sidebar {
container: sidebar / inline-size;
}

Внутри @container можно использовать специальные единицы измерения, привязанные к размеру контейнера:

ЕдиницаЗначение
cqw1% ширины контейнера
cqh1% высоты контейнера
cqi1% inline-размера контейнера (обычно ширины)
cqb1% block-размера контейнера (обычно высоты)
cqminменьшее из cqi и cqb
cqmaxбольшее из cqi и cqb

Пример — шрифт масштабируется плавно вместе с контейнером:

@container (width > 300px) {
.card h2 {
/* font-size растёт вместе с контейнером */
font-size: max(1.2em, 1em + 2cqi);
}
}

Интерактивный пример 1 — базовые container queries

Заголовок раздела «Интерактивный пример 1 — базовые container queries»

Перетащи ползунок, чтобы изменить ширину контейнера и увидеть, как карточка меняет layout:


Интерактивный пример 2 — именованные контейнеры

Заголовок раздела «Интерактивный пример 2 — именованные контейнеры»

Один и тот же компонент .card в двух разных контейнерах — sidebar и main. Каждый контейнер настроен независимо:


Единицы cqi позволяют шрифту и элементам плавно масштабироваться вместе с контейнером — без медиа-точек: