Container Queries: The End of Media Queries?
Присаживайся, наливай кофе. Сегодня разберем тему, которая прямо сейчас меняет правила игры в адаптивной верстке. Если ты до сих пор верстаешь компоненты, оглядываясь исключительно на ширину экрана девайса, у меня для тебя плохие новости: ты застрял в прошлом десятилетии. Но хорошая новость в том, что мы это сейчас исправим.
Представь классическую боль: ты написал шикарную карточку товара. В сетке на всю ширину она выглядит идеально, в три колонки — сносно. Но стоит засунуть ее в узкий сайдбар — и всё едет к чертям. Текст слипается, кнопка вылезает за границы, картинка сжимается в пиксельную кашу. Знакомо? Давай разберем, как мы решали это раньше и как элегантно закрыть этот вопрос раз и навсегда.
Как мы страдали раньше
До появления современных CSS-свойств у нас был только один инструмент — Media Queries. И это был сплошной костыльный театр. Нам приходилось плодить десятки сущностей, чтобы один и тот же компонент адекватно смотрелся в разных частях сайта. Как мы выкручивались?
- Миллион модификаторов. Мы писали тонны классов:
.card--sidebar,.card--hero,.card--grid-3-col. Стоило дизайнеру перетащить карточку в другое место, и приходилось переписывать стили в CSS. - JS-костыли. Использовали
ResizeObserverв JavaScript, чтобы отслеживать размеры конкретного DOM-элемента и навешивать классы на лету. Привет, Layout Thrashing, просадка FPS и дерганая анимация при изменении размера окна! - Привязка к вьюпорту. Мы пытались угадать поведение компонента, зная лишь ширину экрана телефона или десктопа. Но ведь карточке в сайдбаре плевать, открыт сайт на мониторе 4K или на iPhone. Ей важны только те 300 пикселей, которые выделил под нее сайдбар.
Как мы уже упоминали в первой части нашего разбора Container Queries, медиа-запросы изначально создавались для макро-разметки страниц, а не для микро-адаптива независимых компонентов. Пытаться верстать ими сложные интерфейсы — это как забивать гвозди микроскопом.
Как делать правильно в 2026 году
Сегодня Container Queries (контейнерные запросы) стали полноценным стандартом, который поддерживается всеми современными браузерами. Идея проста до гениальности: мы говорим элементу реагировать не на ширину экрана (viewport), а на ширину его непосредственного родителя (контейнера).
Теперь наш компонент становится по-настоящему изолированным. Мы можем закинуть его в сайдбар, в подвал, в модалку или в сложную сетку Grid — он сам поймет, сколько у него свободного места, и перестроится под него. Кстати, для сложных раскладок внутри карточки идеально зайдет связка с Subgrid — подробнее об этом читай в нашем полном руководстве по CSS Grid Subgrid.
Чтобы магия заработала, нам нужно сделать всего два шага:
- Объявить родительский элемент контейнером с помощью свойства
container-type. - Написать стили для дочернего элемента внутри правила
@containerвместо привычного@media.
Готовый сниппет кода
Давай закодим адаптивную карточку, которая легким движением руки превращается из горизонтальной в вертикальную, как только ей становится тесно. Обрати внимание, как изящно это работает без единой строчки на JS и без медиа-запросов.
<!-- HTML-разметка -->
<div class="card-wrapper">
<article class="product-card">
<img src="product.jpg" alt="Product" class="product-card__img">
<div class="product-card__content">
<h3 class="product-card__title">Крутой девайс</h3>
<p class="product-card__desc">Этот девайс изменит твою жизнь раз и навсегда.</p>
<button class="product-card__btn">Купить</button>
</div>
</article>
</div>
<!-- CSS-стили -->
<style>
/* 1. Делаем обертку контейнером */
.card-wrapper {
container-type: inline-size;
container-name: card-container;
width: 100%;
}
/* 2. Базовые стили для узкого контейнера (вертикальный вид) */
.product-card {
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px;
background: #f5f5f7;
border-radius: 12px;
}
.product-card__img {
width: 100%;
height: auto;
aspect-ratio: 16/9;
object-fit: cover;
border-radius: 8px;
}
/* 3. Магия: если контейнер шире 500px, делаем карточку горизонтальной */
@container card-container (min-width: 500px) {
.product-card {
flex-direction: row;
align-items: center;
}
.product-card__img {
width: 180px;
aspect-ratio: 1/1;
}
}
</style>
Частая ошибка новичков
Главный капкан, в который стабильно попадают мидлы при первом знакомстве с контейнерами — это попытка повесить container-type и сам запрос @container на один и тот же элемент.
Запомни железобетонное правило: компонент не может опрашивать сам себя. Если ты напишешь:
.product-card {
container-type: inline-size;
}
@container (min-width: 500px) {
.product-card {
/* ТАК НЕ РАБОТАЕТ! */
}
}
Браузер просто проигнорирует эти стили. Почему? Потому что изменение стилей элемента внутри медиа-запроса может изменить его собственный размер, что вызовет бесконечный цикл перерендеринга (свойство меняет размер -> размер меняет стили -> стили меняют размер). Браузеры умные, они пресекают это на корню. Контейнером всегда должен быть родительский элемент (обертка), а стилизовать мы должны его потомков.
Убивают ли Container Queries медиа-запросы окончательно? Нет. Media Queries всё еще идеальны для глобальной сетки страницы, темизации (dark mode) и системных настроек пользователя. Но для верстки независимых компонентов контейнеры — это безоговорочный стандарт современной веб-разработки.
🔥 Больше фишек, готовых сниппетов и передовых подходов к CSS мы публикуем в нашем Telegram-канале. Подписывайтесь, чтобы не пропустить!