Container Queries: The End of Media Queries?

Наливай кофе, давай поговорим о боли

Представь классическую задачу: тебе нужно сверстать красивую карточку товара. Дизайнер хочет, чтобы в узком сайдбаре она выглядела как вертикальный стек, в сетке каталога — как стандартная плитка, а внизу страницы растягивалась на всю ширину в горизонтальный формат. Знакомо? Еще бы.

Раньше мы сразу открывали файл стилей и начинали писать медиа-запросы. Но вот незадача: 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 (контейнерные запросы). Их концепция гениальна и проста: мы объявляем родительский элемент «контейнером», а дочерние элементы стилизуем в зависимости от того, сколько места этот контейнер им выделил.

Для этого нам нужны всего два шага:

  1. Задать родителю свойство container-type: inline-size (чтобы отслеживать его ширину).
  2. Использовать директиву @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-канале. Подписывайтесь, чтобы не пропустить!

🚀 Прокачай свой код

Готовые CSS-сниппеты, разбор продвинутых фишек и эксклюзивные материалы — в нашем Telegram-канале.

Подписаться
error: Content is protected !!
Прокрутить вверх