Медиазапросы смотрят на ширину всего экрана. Но представьте карточку товара, которая используется и в узкой боковой колонке, и в широкой основной области. По размеру экрана обе выглядят одинаково, хотя места вокруг у них совершенно разное — и в узкой колонке карточку хотелось бы показать компактнее. Медиазапрос тут бессилен: он не знает, сколько места у конкретного блока. Эту задачу решают контейнерные запросы @container — они позволяют компоненту подстраиваться под размер своего родителя, а не всего экрана. Это делает компоненты по-настоящему переиспользуемыми.
После этого урока вы сможете строить компоненты, которые адаптируются к доступному им месту независимо от размера окна, — современный и очень удобный подход к отзывчивой вёрстке.
Что уже умеем / что добавим
Вы умеете адаптировать макет под экран через @media. Теперь научимся адаптировать отдельные компоненты под их контейнер. В сквозном проекте мы сделаем карточку услуги самостоятельно перестраивающейся: в широком месте — картинка слева и текст справа, в узком — всё в столбик.
Что вы узнаете в рамках статьи
- Чем контейнерные запросы отличаются от медиазапросов.
- Как объявить контейнер через
container-type. - Как писать правило
@containerпо ширине родителя. - Когда контейнерные запросы удобнее медиазапросов.
Ключевые термины
- Контейнерный запрос — правило, срабатывающее по размеру родителя-контейнера.
container-type— свойство, объявляющее элемент контейнером для запросов.@container— правило, применяющее стили при условии на размер контейнера.container-name— необязательное имя контейнера для адресных запросов.
Медиа против контейнера
Разница проста, но принципиальна. Медиазапрос @media спрашивает: «какова ширина экрана?» Контейнерный запрос @container спрашивает: «сколько места у моего родителя?» Первый смотрит наружу, на окно; второй — на ближайший контейнер вокруг компонента.
Это меняет саму логику. Один и тот же компонент, помещённый в разные места страницы, с медиазапросами выглядел бы одинаково (экран-то один). С контейнерными запросами он подстроится под каждое место: узкий контейнер — компактный вид, широкий — развёрнутый. Компонент становится независимым и переиспользуемым — его можно вставить куда угодно, и он сам примет верную форму.
Объявляем контейнер
Чтобы по элементу можно было задавать запросы, его нужно объявить контейнером свойством container-type. Чаще всего используют значение inline-size — «отслеживать ширину»:
.card-wrap {
container-type: inline-size;
}
Теперь .card-wrap — контейнер, и вложенные в него элементы могут реагировать на его ширину. Важно: запросы будут смотреть именно на этот объявленный контейнер, а не на экран. Обычно контейнером делают обёртку вокруг компонента, а сам компонент (карточку) адаптируют внутри. По желанию контейнеру можно дать имя через container-name, чтобы адресовать запросы конкретно ему, — но для одного контейнера это не обязательно.
Пишем @container
Правило @container очень похоже на @media, только условие относится к контейнеру, а не к экрану:
.card {
display: grid;
grid-template-columns: 1fr;
}
@container (min-width: 400px) {
.card {
grid-template-columns: 120px 1fr;
}
}
Читается так: «если контейнер шире 400 пикселей, покажи карточку в две колонки — картинка и текст рядом». Пока родитель уже 400px, карточка остаётся в один столбец. Обратите внимание: мы нигде не упоминаем размер экрана — важна только ширина контейнера .card-wrap. Поставьте такую карточку в узкую боковую колонку — она свернётся в столбик; поставьте в широкую область — развернётся в две колонки. И всё это на одном и том же экране.
Когда что выбирать
Медиазапросы и контейнерные запросы не заменяют друг друга, а дополняют. Для общего каркаса страницы — расположения крупных зон, глобальных отступов, числа основных колонок — по-прежнему удобны медиазапросы: они про экран в целом.
Для отдельных переиспользуемых компонентов — карточек, виджетов, блоков, которые встречаются в разных местах с разной шириной, — лучше подходят контейнерные запросы: компонент сам знает, как повести себя в доступном месте. Практическое правило: макет целиком — @media, самодостаточный компонент — @container. Контейнерные запросы поддержаны современными браузерами и уже готовы к применению в реальных проектах.
Применяем в проекте
Сделаем карточку услуги самонастраивающейся. Обернём её в контейнер и опишем: в узком месте содержимое идёт в столбик, в широком — картинка слева, текст справа. Теперь карточку можно ставить и в основную сетку, и в узкую колонку — она подстроится сама.
.card-wrap {
container-type: inline-size;
}
.card {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
}
@container (min-width: 400px) {
.card {
grid-template-columns: 140px 1fr;
align-items: center;
}
}
Поместите такую карточку в широкую область — картинка встанет слева, текст справа. Перенесите её в узкую колонку — та же карточка свернётся в аккуратный столбик, хотя размер экрана не менялся. Компонент стал по-настоящему переиспользуемым: он реагирует на своё окружение, а не на окно. Это большой шаг к профессиональной, компонентной вёрстке.
Частые ошибки
- Забыли
container-type.
Без объявления контейнера правило@containerне на что опереться и не сработает. - Запрос к самому себе.
Контейнером делают родителя-обёртку, а адаптируют вложенный компонент; элемент не может опрашивать собственный размер как контейнер. - Подмена медиазапросов.
Для глобального каркаса страницы@mediaобычно уместнее;@container— для компонентов. - Ожидание реакции на экран.
@containerсмотрит на родителя, а не на окно; для условий по экрану нужен@media.
Итоги
Замечательно — вы освоили один из самых современных инструментов вёрстки! Вы поняли, чем контейнерные запросы отличаются от медиазапросов, научились объявлять контейнер через container-type и писать правила @container по ширине родителя. Ваша карточка услуги теперь подстраивается под место, куда её поставили, — она стала самостоятельным переиспользуемым компонентом. Это тот уровень, на котором думают в настоящих дизайн-системах.
Отличная работа! В следующем уроке мы добавим гибкости самим размерам: изучим единицы %, vw/vh и функции clamp(), min(), max(), которые позволяют элементам плавно масштабироваться без единого медиазапроса.