Container Queries: The End of Media Queries?

Container Queries: Конец эпохи Media Queries?

Присаживайся, наливай кофе. Давай серьезно поговорим про адаптив. Сколько раз ты ловил себя на мысли: «Блин, почему я должен писать медиа-запрос под ширину экрана в 768 пикселей, если мне просто нужно, чтобы карточка товара внутри узкого сайдбара выглядела компактно, а в широком блоке контента — разворачивалась во всю ширь?»

Media Queries долгое время были нашим единственным спасением, но у них есть фундаментальный концептуальный изъян: они мыслят категориями вьюпорта (экрана девайса), а не реального окружения компонента. В эпоху компонентного подхода и микрофронтендов это превратилось в постоянную головную боль. Но решение уже здесь, оно созрело и готово к продакшену. Это Container Queries (контейнерные запросы).

Как мы страдали раньше

Раньше, чтобы решить эту проблему, нам приходилось использовать либо тонны костылей в CSS, либо подключать тяжелую артиллерию на JavaScript. Вспомни эти классические подходы:

  • Модификаторы на все случаи жизни: Мы плодили классы вроде .card--sidebar, .card--hero или .card--grid-3-col. Стоило менеджеру перенести карточку в другое место, как разметка ломалась, а стили приходилось переписывать заново.
  • Слежка через JS (ResizeObserver): Мы вешали слушатели на изменение размеров элементов, чтобы динамически вешать классы. Привет, лишний JS-код, микродерганья интерфейса (Layout Shifts) и просадка производительности на слабых девайсах!
  • Пляски с Flexbox и Grid: Мы пытались выжать максимум из формул с clamp(), minmax() и автозаполнением, чтобы элементы как-то сами переносились. Но если внутри карточки нужно было не просто перестроить сетку, а радикально поменять структуру (например, скрыть описание или уменьшить шрифт), этот подход давал сбой. Кстати, если хочешь прокачать свои навыки работы со сложными сетками, почитай наш подробный гайд по Mastering CSS Grid Subgrid — это идеальный напарник для современных интерфейсов.

Как делать правильно в 2026 году

Забудь про костыли. Сегодня Container Queries поддерживаются всеми современными браузерами (база — более 90% по Can I Use). Логика проста: мы объявляем элемент-родитель контейнером, а его дочерние элементы стилизуем в зависимости от того, сколько места этому родителю выделено на экране.

Для этого используется свойство container-type. Обычно мы задаем значение inline-size, чтобы отслеживать изменение ширины контейнера. А дальше используем директиву @container так же просто, как привычный @media.

Давай посмотрим на живой пример карточки, которая полностью меняет свой расклад в зависимости от ширины родительского блока.

Готовый сниппет кода

<!-- HTML-разметка -->
<div class="card-container">
  <article class="product-card">
    <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=400" alt="Кроссовки" class="product-card__image">
    <div class="product-card__content">
      <h3 class="product-card__title">Стильные кроссовки</h3>
      <p class="product-card__desc">Легкие, прочные и идеально подходящие для ежедневных тренировок в городских условиях.</p>
      <span class="product-card__price">8 900 ₽</span>
    </div>
  </article>
</div>

<style>
/* 1. Объявляем родительский контейнер */
.card-container {
  container-type: inline-size;
  container-name: product-wrapper; /* Имя опционально, но полезно для вложенности */
  width: 100%;
}

/* Base-стили для "узкого" состояния (мобильный вид по умолчанию) */
.product-card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 16px;
  border: 1px solid #e0e0e0;
  border-radius: 12px;
  background: #fff;
}

.product-card__image {
  width: 100%;
  height: 200px;
  object-fit: cover;
  border-radius: 8px;
}

.product-card__desc {
  display: none; /* Скрываем текст в узком контейнере */
}

/* 2. Магия контейнерных запросов */
@container product-wrapper (min-width: 500px) {
  .product-card {
    flex-direction: row;
    align-items: center;
    gap: 24px;
  }

  .product-card__image {
    width: 150px;
    height: 150px;
  }

  .product-card__desc {
    display: block; /* Показываем описание, когда места достаточно */
    margin: 8px 0;
    color: #666;
  }
}
</style>

Частая ошибка новичков

Самый распространенный факап, на котором спотыкаются мидлы, впервые пробующие контейнерные запросы — это попытка изменить стили самого контейнера внутри его собственного запроса. Запомни:

Нельзя стилизовать контейнер на основе его собственных размеров.

Например, вот такой код работать не будет или приведет к бесконечному циклу рендеринга (infinite loop):

@container (min-width: 500px) {
  /* Браузер проигнорирует это изменение ширины самого контейнера! */
  .card-container {
    width: 100%; 
  }
}

Браузер должен точно знать размеры контейнера, чтобы применить стили к его дочерним элементам. Если стили дочерних элементов повлияют на размер самого контейнера (например, через автоматическую высоту), начнется бесконечный цикл расчетов, и браузер просто заблокирует выполнение стилей. Поэтому контейнер всегда определяет правила игры, а дети по этим правилам живут.

Убивают ли Container Queries привычные Media Queries? Нет. Нам все еще нужны медиа-запросы для глобальных вещей: глобальной сетки лейаута, изменения размера шрифта у тега html, настройки темы оформления или ориентации экрана. Но для верстки независимых UI-компонентов Container Queries — это абсолютный и бесповоротный стандарт уже сейчас.

🔥 Больше фишек, готовых сниппетов и передовых подходов к CSS мы публикуем в нашем Telegram-канале. Подписывайтесь, чтобы не пропустить!

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

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

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