Эра ментального сдвига: почему Media Queries больше не тянут
Привет! Присаживайся, наливай кофе. Давай сегодня поговорим по душам о наболевшем. Помнишь, как мы годами строили адаптивную верстку? Нам вбивали в голову: «Думай сеткой устройства!». Мы писали тонны медиа-запросов под iPhone, iPad, стандартный Full HD монитор и тот странный ультраширокий экран нашего генерального директора. Но давай признаем: медиа-запросы — это костыль планетарного масштаба для компонентного подхода.
В чем реальная боль? Мы пишем изолированную карточку товара. В сетке на три колонки она выглядит шикарно. В сайдбаре она должна сжаться до вертикального формата, а в шапке профиля — растянуться на всю ширину и превратиться в горизонтальный баннер. С классическими Media Queries тебе приходилось либо плодить миллион CSS-классов вроде .card--sidebar и .card--hero, либо связывать стили с контекстом родителя. Но компонент не должен знать, где он лежит. Он должен сам адаптироваться под выделенное ему пространство. И вот тут на сцену выходят Container Queries.
Как мы страдали раньше: костыли, JS и верстка «на ощупь»
Давай вспомним этот «вьетнамский синдром» верстки. Чтобы заставить элемент менять свой вид в зависимости от размера его родителя, а не экрана, нам приходилось выкручиваться как только можно:
- ResizeObserver на JavaScript. Мы вешали слушатели событий на каждый чих, дергали DOM, замеряли ширину родительского контейнера в пикселях и динамически навешивали классы вроде
.is-smallили.is-large. Это вызывало дикий Layout Thrashing, просаживало FPS и превращало код в нечитаемую кашу. - Множественные модификаторы. Твой CSS превращался в портянку из селекторов типа
.sidebar .card,.grid-3-col .card,.footer .card. Компонент терял всякую изолированность. Если тебе интересно, как мы выжимали максимум из сложных сеток в те темные времена, загляни в наш гайд по CSS Grid Subgrid — там тоже немало боли и красивых решений. - Попытки сделать все на флексах. Мы использовали безумные формулы с
calc()иflex-basis, надеясь, что элементы перенесутся «как-нибудь красиво». Спойлер: красиво получалось редко.
Мы подробно разбирали философию ухода от этих костылей в статье Container Queries: The End of Media Queries?, но сегодня давай посмотрим, как применять это на практике без лишней теории.
Как делать правильно в 2026 году: Container Queries на практике
Сейчас поддержка контейнерных запросов в браузерах стала абсолютным стандартом. Нам больше не нужно бояться за старые Safari или Chrome. Логика работы невероятно проста и изящна: мы объявляем родительский элемент «контейнером», а дочерние элементы начинают следить за его размерами, игнорируя ширину экрана.
Для этого используется свойство container-type (обычно со значением inline-size, чтобы следить только за шириной) и, опционально, container-name, чтобы задать контейнеру имя и не путаться в сложных вложенностях. А дальше мы просто пишем @container вместо привычного @media. Более того, у нас появились новые единицы измерения — cqw (1% от ширины контейнера) и cqh (1% от высоты контейнера), которые делают верстку по-настоящему резиновой.
Готовый сниппет кода
Давай соберем простую, но показательную карточку. В зависимости от того, в какой контейнер мы ее положим, она будет автоматически перестраиваться из вертикального формата в горизонтальный. Обрати внимание: мы пишем стили для самой карточки ОДИН раз, без привязки к классам раскладки.
<!-- HTML-разметка -->
<div class="layout-grid">
<!-- Узкий родитель (например, сайдбар) -->
<div class="widget-area">
<div class="card">
<img src="https://picsum.photos/400/300" alt="Превью" class="card__img">
<div class="card__content">
<h3 class="card__title">Стильный адаптивный компонент</h3>
<p class="card__text">Этот компонент автоматически меняет раскладку в зависимости от ширины своего родителя.</p>
</div>
</div>
</div>
<!-- Широкий родитель (например, контентная область) -->
<div class="main-area">
<div class="card">
<img src="https://picsum.photos/400/300" alt="Превью" class="card__img">
<div class="card__content">
<h3 class="card__title">Стильный адаптивный компонент</h3>
<p class="card__text">Этот компонент автоматически меняет раскладку в зависимости от ширины своего родителя.</p>
</div>
</div>
</div>
</div>
<style>
/* 1. Определяем родительские элементы как контейнеры */
.widget-area, .main-area {
container-type: inline-size;
container-name: card-container;
border: 2px dashed #ccc;
padding: 1rem;
margin-bottom: 2rem;
}
/* Ограничим размеры для наглядности демонстрации */
.widget-area { max-width: 350px; }
.main-area { max-width: 800px; }
/* 2. Базовые стили карточки (по умолчанию для узких контейнеров) */
.card {
display: flex;
flex-direction: column;
gap: 16px;
background: #fff;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
font-family: sans-serif;
}
.card__img {
width: 100%;
height: 200px;
object-fit: cover;
}
.card__content {
padding: 16px;
}
.card__title {
margin: 0 0 8px 0;
font-size: 1.2rem;
color: #222;
}
.card__text {
margin: 0;
font-size: 0.9rem;
color: #666;
line-height: 1.4;
}
/* 3. Магия Container Queries! */
/* Если ширина контейнера card-container больше 500px, переключаемся на горизонтальный вид */
@container card-container (min-width: 500px) {
.card {
flex-direction: row;
align-items: center;
}
.card__img {
width: 250px;
height: 100%;
min-height: 180px;
}
.card__title {
/* Используем контейнерные единицы для динамического шрифта */
font-size: calc(1rem + 1cqw);
}
}
</style>
Частая ошибка новичков: эффект бесконечной петли
Самый частый капкан, в который попадают мидлы, впервые пробуя Container Queries — это попытка изменить размеры самого контейнера внутри контейнерного запроса.
Смотри, как делать категорически нельзя:
@container my-container (min-width: 400px) {
/* Ошибка! Изменение ширины контейнера ломает логику расчета */
.my-container {
width: 300px;
}
}
Что здесь происходит? Браузер видит, что ширина контейнера больше 400px, применяет стиль и уменьшает его ширину до 300px. Но теперь ширина меньше 400px! Браузер отменяет стиль, ширина снова становится больше 400px… Привет, бесконечный цикл и зависший рендеринг.
Золотое правило Container Queries: мы опрашиваем контейнер (родителя), но стилизуем его содержимое (детей). Сам контейнер внутри @container менять свои геометрические размеры (ширину, высоту, padding, влияющий на content-box) не должен. Если нужно изменить сам контейнер, оберни его в еще один внешний элемент и сделай контейнером именно его.
Ну что, теперь ты видишь, что медиа-запросы постепенно уходят на покой и остаются только для глобальных вещей вроде темной темы или базовой раскладки страницы? Пиши чистый, модульный CSS и не усложняй себе жизнь старыми хаками!
🔥 Больше фишек, готовых сниппетов и передовых подходов к CSS мы публикуем в нашем Telegram-канале. Подписывайтесь, чтобы не пропустить!