Container Queries: The End of Media Queries?
Присаживайся, наливай кофе. Сегодня поговорим о вещи, которая тихо, но бесповоротно изменила то, как мы пишем адаптивный интерфейс. Да-да, я про Container Queries (контейнерные запросы). В 2026 году этот инструмент стал абсолютным стандартом, но я до сих пор вижу, как разработчики по привычке обмазывают проект медиа-запросами вдоль и поперек. Давай разберемся, почему Media Queries больше не царь горы, и как наконец-то начать писать по-настоящему независимые компоненты.
Представь классическую боль: ты верстаешь карточку товара. В сетке сайта она может лежать в узкой боковой колонке, в стандартной сетке из трех колонок по центру или растягиваться во всю ширину экрана на детальной странице. Раньше, чтобы карточка выглядела адекватно в каждом из этих сценариев, тебе приходилось писать тонну специфичных классов-модификаторов или привязываться к ширине вьюпорта через @media (max-width: 1200px). Но ведь карточке абсолютно плевать на ширину экрана смартфона или монитора! Ей важно только одно: сколько места выделил под нее родительский блок.
Как мы страдали раньше
Вспомни эти темные времена. Когда нам нужно было адаптировать элемент под его окружение, мы извращались как могли. Вот стандартный джентльменский набор костылей до появления современных CSS-свойств:
- Раздутые селекторы-модификаторы: Мы писали громоздкие конструкции в духе
.sidebar .card { flex-direction: column; }. Это ломало инкапсуляцию компонентов, превращая стили в неуправляемую лапшу, которую страшно трогать через полгода поддержки. - JS-подорожники (ResizeObserver): Если дизайн требовал кардинальной перестройки элемента в зависимости от его ширины, мы вешали JS-слушатели. Они постоянно замеряли ширину блока, дергали DOM, вешали классы вроде
.is-small, вызывали адские перерисовки (reflow) и сильно били по перформансу. - Попытки выехать на математике: Иногда мы пытались сгладить углы, настраивая плавный адаптив шрифтов и отступов. Да, математические функции в CSS: clamp, min, max отлично справляются с масштабированием, но полностью изменить сетку или спрятать/показать элементы на основе размеров родителя они физически не способны.
Как делать правильно в 2026 году
Контейнерные запросы решают эту проблему элегантно. Теперь компонент сам решает, как ему выглядеть, ориентируясь на размеры своего непосредственного «дома» — контейнера. Всё, что тебе нужно сделать, это объявить родительский элемент контейнером с помощью свойства container-type, а затем использовать директиву @container вместо привычной @media.
Кстати, если твоя сетка усложняется настолько, что карточки должны идеально выстраиваться по внутренним колонкам родительского грида, в связке с контейнерными запросами круто работает технология subgrid. Если ты еще не внедрил её в свой стек, рекомендую почитать статью про CSS Subgrid — это сэкономит тебе кучу нервов при работе со сложными макетами.
Давай посмотрим на чистый и понятный пример реализации.
Готовый сниппет кода
/* 1. Сначала подготавливаем родителя, делая его контекстом контейнера */
.card-wrapper {
container-type: inline-size;
container-name: product-card-container;
width: 100%;
}
/* 2. Стили по умолчанию (для широкого контейнера — горизонтальный вид) */
.product-card {
display: flex;
align-items: center;
gap: 24px;
padding: 16px;
background: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.product-card img {
width: 150px;
height: 150px;
object-fit: cover;
border-radius: 8px;
}
/* 3. Адаптируем компонент, когда ширина КОНТЕЙНЕРА становится меньше 450px */
@container product-card-container (max-width: 450px) {
.product-card {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.product-card img {
width: 100%;
height: 200px;
}
}
Частая ошибка новичков
Самый частый факап, на котором спотыкаются разработчики при первом знакомстве с Container Queries — это попытка применить контейнерное правило к самому контейнеру. Запомни раз и навсегда: нельзя изменять стили контейнера внутри его собственного контейнерного запроса.
Почему? Да потому что это вызовет бесконечный цикл рендеринга. Браузер уменьшает контейнер -> срабатывает `@container` -> стиль внутри `@container` уменьшает ширину этого же контейнера еще сильнее -> браузер падает в бесконечную рекурсию. Чтобы защитить рендеринг, браузеры просто проигнорируют такие правила.
Контейнерный запрос всегда должен нацеливаться на дочерние элементы внутри этого контейнера. Ты вешаешь container-type на обертку, а внутри @container стилизуешь дочерние классы. Только так это работает стабильно, предсказуемо и максимально производительно.
🔥 Больше фишек, готовых сниппетов и передовых подходов к CSS мы публикуем в нашем Telegram-канале. Подписывайтесь, чтобы не пропустить!