Container Queries: The End of Media Queries?

Настоящая свобода компонентов, или Почему Media Queries больше не тянут

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

Раньше твоя реакция была предсказуемой: тихий вздох и подготовка к написанию тонны медиа-запросов, завязанных на ширину экрана (viewport). Но ведь это абсурд! Карточке абсолютно плевать, какой ширины экран у пользователя — 1920px или 320px. Ей важно лишь одно: сколько пространства выделил ей родительский контейнер. Медиа-запросы изначально создавались для стилизации страниц целиком, но в эпоху компонентного подхода в React, Vue или Web Components они стали главным источником костылей. Container Queries полностью закрывают эту боль, меняя правила игры раз и навсегда.

Как мы страдали раньше: Эра костылей и спагетти-классов

До того как Container Queries получили глобальную поддержку в браузерах, нам приходилось выкручиваться как богам костыльного программирования. Вспомни эти классические подходы, от которых сегодня бросает в дрожь:

  • Модификаторы на все случаи жизни: Мы плодили классы вроде .card--sidebar, .card--grid-3-col, .card--hero. Стоило менеджеру переместить компонент в другую секцию, как верстка ломалась, и приходилось дописывать новые стили.
  • Слежка через JavaScript: Использование ResizeObserver или, упаси боже, глобального события window.onresize. Мы заставляли JS вычислять размеры блоков, дергать DOM, вешать дата-атрибуты вроде data-width="small" и ловить Layout Thrashing (избыточный пересчет геометрии страницы), который нещадно тормозил интерфейс.
  • Дублирование разметки: Когда стилями обойтись не получалось, мы просто рендерили два разных компонента и скрывали один из них через display: none в зависимости от брейкпоинта. Настоящий кошмар для SEO и доступности (accessibility).

Для идеального выравнивания контента внутри таких сложных, прыгающих по сетке карточек, сегодня отлично подходит Subgrid. Он решает проблему синхронизации вложенных сеток, избавляя от необходимости прописывать фиксированные высоты для шапок и футеров внутри карточек.

Как делать правильно в 2026 году: Пишем компонент будущего

Забудь про viewport-зависимость. Современный подход требует мыслить изолированными модулями. Мы объявляем родительский элемент «контекстом контейнера» (container context) с помощью свойства container-type, а затем пишем стили для дочерних элементов, которые будут реагировать исключительно на физический размер этого родителя.

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

Давай посмотрим на лаконичную и современную реализацию адаптивной карточки.

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

<!-- HTML-структура -->
<div class="card-wrapper">
  <article class="product-card">
    <img src="https://picsum.photos/400/300" alt="Product" class="product-card__image" />
    <div class="product-card__content">
      <h3 class="product-card__title">Революционный девайс</h3>
      <p class="product-card__desc">Этот девайс изменит ваше представление о веб-разработке раз и навсегда.</p>
      <button class="product-card__btn">Купить</button>
    </div>
  </article>
</div>

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

/* Base-styles (мобильный вид / узкий контейнер) */
.product-card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 16px;
  background: #f9f9f9;
  border-radius: 12px;
  border: 1px solid #eee;
}

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

/* 2. Магия Container Queries для средних размеров */
@container card-container (min-width: 450px) {
  .product-card {
    padding: 24px;
    background: #f0f4f8;
  }
  .product-card__title {
    font-size: 1.5rem;
  }
}

/* 3. Горизонтальный вид для широких контейнеров */
@container card-container (min-width: 700px) {
  .product-card {
    flex-direction: row;
    align-items: center;
    gap: 32px;
  }
  .product-card__image {
    width: 250px;
    height: 180px;
  }
  .product-card__content {
    flex: 1;
  }
}
</style>

Частая ошибка новичков: Петля бесконечности

Самый жесткий капкан, в который попадают джуны и мидлы при первом знакомстве с Container Queries — это попытка повесить container-type и @container-запрос на один и тот же элемент.

Запомни железное правило: Контейнер не может стилизовать сам себя на основе своего размера.

Почему? Представь ситуацию: ты пишешь, что если ширина элемента больше 500px, его шрифт должен увеличиться. Увеличение шрифта распирает элемент, его ширина становится 510px. Браузер применяет стили. Но что если в этих стилях меняется padding, который сужает элемент обратно до 490px? Браузер должен отменить стили. И так по кругу до бесконечности (бесконечный цикл рендеринга). Чтобы избежать этого коллапса, спецификация CSS строго запрещает элементу-контейнеру реагировать на свои собственные медиа-параметры. Запрос всегда должен идти к родителю (как в примере выше: мы объявили контейнером .card-wrapper, а стилизуем его дочерний элемент .product-card).

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

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

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

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

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