Наливай кофе, давай поговорим о боли
Представь классическую задачу: тебе нужно сверстать красивую карточку товара. Дизайнер хочет, чтобы в узком сайдбаре она выглядела как вертикальный стек, в сетке каталога — как стандартная плитка, а внизу страницы растягивалась на всю ширину в горизонтальный формат. Знакомо? Еще бы.
Раньше мы сразу открывали файл стилей и начинали писать медиа-запросы. Но вот незадача: Media Queries смотрят на размер вьюпорта (экрана), а не на реальный размер родительского блока, в который вставлена наша карточка. Если экран большой (например, 1920px), но карточка зажата в узкой боковой панели, медиа-запрос выдаст нам стили для десктопа, и верстка разъедется в кашу. Чтобы детально разобраться, почему медиа-запросы больше не могут в одиночку тащить весь респонсив, почитай наш подробный разбор в статье Container Queries: The End of Media Queries?. А сейчас давай вспомним, как мы выкручивались из этой ситуации.
Как мы страдали раньше
Чтобы решить эту проблему, frontend-разработчики годами изобретали велосипеды и использовали довольно грязные хаки:
- Миллион модификаторов. Мы плодили классы вроде
.card--sidebar,.card--grid,.card--full-width. В итоге компонент терял свою независимость, а разработчику приходилось вручную следить, где именно на странице рендерится карточка, чтобы прокинуть правильный класс. - JS-костыли через ResizeObserver. Мы вешали слушатели на изменение размеров элементов. Это приводило к микро-фризам при ресайзе, дерганой анимации, лишнему коду в бандле и вечной борьбе с Layout Shift.
- Дублирование компонентов. В особо запущенных случаях для разных зон сайта писались фактически разные компоненты, что превращало поддержку проекта в ад.
Как делать правильно в 2026 году
Забудь про костыли. Эпоха, когда адаптивность зависела исключительно от размеров экрана, официально ушла в прошлое. Теперь у нас есть Container Queries (контейнерные запросы). Их концепция гениальна и проста: мы объявляем родительский элемент «контейнером», а дочерние элементы стилизуем в зависимости от того, сколько места этот контейнер им выделил.
Для этого нам нужны всего два шага:
- Задать родителю свойство
container-type: inline-size(чтобы отслеживать его ширину). - Использовать директиву
@containerвместо привычной@mediaдля дочерних элементов.
Благодаря этому компонент становится по-настоящему изолированным. Ты можешь закинуть его в любое место на странице, и он сам адаптируется под выделенное пространство. О том, как эта технология меняет архитектуру современных UI-библиотек, мы писали в материале Container Queries: The End of Media Queries? — крайне рекомендую к ознакомлению для расширения кругозора.
Готовый сниппет кода
Давай посмотрим на чистый и понятный пример. Мы создадим контейнер для карточки и заставим ее менять направление флекса со столбца на строку, как только ширина контейнера превысит 500 пикселей.
/* 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-color: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.product-card__image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
border-radius: 8px;
}
/* 3. Магия: меняем раскладку в зависимости от ширины КОНТЕЙНЕРА */
@container card-container (min-width: 500px) {
.product-card {
flex-direction: row;
align-items: center;
}
.product-card__image {
width: 180px;
height: 120px;
aspect-ratio: auto;
}
}
Частая ошибка новичков
Когда мидлы начинают впервые щупать Container Queries, они почти всегда совершают одну и ту же ошибку: пытаются изменить стили самого контейнера внутри его же запроса.
Запомни железное правило: запрос @container может изменять стили только потомков этого контейнера, но не сам контейнер!
Если ты напишешь что-то вроде:
@container (min-width: 500px) {
.card-wrapper {
width: 600px; /* ТАК ДЕЛАТЬ НЕЛЬЗЯ */
}
}
Браузер просто проигнорирует это правило. И это логично: если бы контейнер мог менять свой размер в зависимости от своего же размера, мы бы получили бесконечный цикл рендеринга (infinite loop). Браузер просто завис бы, пытаясь высчитать бесконечные изменения.
Используй контейнерные запросы с умом, инкапсулируй компоненты и делай свою верстку по-настоящему современной!
🔥 Больше фишек, готовых сниппетов и передовых подходов к CSS мы публикуем в нашем Telegram-канале. Подписывайтесь, чтобы не пропустить!