Container Queries: The End of Media Queries?

Эра ментального сдвига: почему Media Queries больше не тянут

Привет! Присаживайся, наливай кофе. Давай сегодня поговорим по душам о наболевшем. Помнишь, как мы годами строили адаптивную верстку? Нам вбивали в голову: «Думай сеткой устройства!». Мы писали тонны медиа-запросов под iPhone, iPad, стандартный Full HD монитор и тот странный ультраширокий экран нашего генерального директора. Но давай признаем: медиа-запросы — это костыль планетарного масштаба для компонентного подхода.

В чем реальная боль? Мы пишем изолированную карточку товара. В сетке на три колонки она выглядит шикарно. В сайдбаре она должна сжаться до вертикального формата, а в шапке профиля — растянуться на всю ширину и превратиться в горизонтальный баннер. С классическими Media Queries тебе приходилось либо плодить миллион CSS-классов вроде .card--sidebar и .card--hero, либо связывать стили с контекстом родителя. Но компонент не должен знать, где он лежит. Он должен сам адаптироваться под выделенное ему пространство. И вот тут на сцену выходят Container Queries.

Как мы страдали раньше: костыли, JS и верстка «на ощупь»

Давай вспомним этот «вьетнамский синдром» верстки. Чтобы заставить элемент менять свой вид в зависимости от размера его родителя, а не экрана, нам приходилось выкручиваться как только можно:

  • ResizeObserver на JavaScript. Мы вешали слушатели событий на каждый чих, дергали DOM, замеряли ширину родительского контейнера в пикселях и динамически навешивали классы вроде .is-small или .is-large. Это вызывало дикий Layout Thrashing, просаживало FPS и превращало код в нечитаемую кашу.
  • Множественные модификаторы. Твой CSS превращался в портянку из селекторов типа .sidebar .card, .grid-3-col .card, .footer .card. Компонент терял всякую изолированность. Если тебе интересно, как мы выжимали максимум из сложных сеток в те темные времена, загляни в наш гайд по CSS Grid Subgrid — там тоже немало боли и красивых решений.
  • Попытки сделать все на флексах. Мы использовали безумные формулы с calc() и flex-basis, надеясь, что элементы перенесутся «как-нибудь красиво». Спойлер: красиво получалось редко.

Мы подробно разбирали философию ухода от этих костылей в статье Container Queries: The End of Media Queries?, но сегодня давай посмотрим, как применять это на практике без лишней теории.

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

Сейчас поддержка контейнерных запросов в браузерах стала абсолютным стандартом. Нам больше не нужно бояться за старые Safari или Chrome. Логика работы невероятно проста и изящна: мы объявляем родительский элемент «контейнером», а дочерние элементы начинают следить за его размерами, игнорируя ширину экрана.

Для этого используется свойство container-type (обычно со значением inline-size, чтобы следить только за шириной) и, опционально, container-name, чтобы задать контейнеру имя и не путаться в сложных вложенностях. А дальше мы просто пишем @container вместо привычного @media. Более того, у нас появились новые единицы измерения — cqw (1% от ширины контейнера) и cqh (1% от высоты контейнера), которые делают верстку по-настоящему резиновой.

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

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

<!-- HTML-разметка -->
<div class="layout-grid">
  <!-- Узкий родитель (например, сайдбар) -->
  <div class="widget-area">
    <div class="card">
      <img src="https://picsum.photos/400/300" alt="Превью" class="card__img">
      <div class="card__content">
        <h3 class="card__title">Стильный адаптивный компонент</h3>
        <p class="card__text">Этот компонент автоматически меняет раскладку в зависимости от ширины своего родителя.</p>
      </div>
    </div>
  </div>

  <!-- Широкий родитель (например, контентная область) -->
  <div class="main-area">
    <div class="card">
      <img src="https://picsum.photos/400/300" alt="Превью" class="card__img">
      <div class="card__content">
        <h3 class="card__title">Стильный адаптивный компонент</h3>
        <p class="card__text">Этот компонент автоматически меняет раскладку в зависимости от ширины своего родителя.</p>
      </div>
    </div>
  </div>
</div>

<style>
/* 1. Определяем родительские элементы как контейнеры */
.widget-area, .main-area {
  container-type: inline-size;
  container-name: card-container;
  border: 2px dashed #ccc;
  padding: 1rem;
  margin-bottom: 2rem;
}

/* Ограничим размеры для наглядности демонстрации */
.widget-area { max-width: 350px; }
.main-area { max-width: 800px; }

/* 2. Базовые стили карточки (по умолчанию для узких контейнеров) */
.card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  background: #fff;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 15px rgba(0,0,0,0.05);
  font-family: sans-serif;
}

.card__img {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.card__content {
  padding: 16px;
}

.card__title {
  margin: 0 0 8px 0;
  font-size: 1.2rem;
  color: #222;
}

.card__text {
  margin: 0;
  font-size: 0.9rem;
  color: #666;
  line-height: 1.4;
}

/* 3. Магия Container Queries! */
/* Если ширина контейнера card-container больше 500px, переключаемся на горизонтальный вид */
@container card-container (min-width: 500px) {
  .card {
    flex-direction: row;
    align-items: center;
  }

  .card__img {
    width: 250px;
    height: 100%;
    min-height: 180px;
  }

  .card__title {
    /* Используем контейнерные единицы для динамического шрифта */
    font-size: calc(1rem + 1cqw); 
  }
}
</style>

Частая ошибка новичков: эффект бесконечной петли

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

Смотри, как делать категорически нельзя:

@container my-container (min-width: 400px) {
  /* Ошибка! Изменение ширины контейнера ломает логику расчета */
  .my-container {
    width: 300px; 
  }
}

Что здесь происходит? Браузер видит, что ширина контейнера больше 400px, применяет стиль и уменьшает его ширину до 300px. Но теперь ширина меньше 400px! Браузер отменяет стиль, ширина снова становится больше 400px… Привет, бесконечный цикл и зависший рендеринг.

Золотое правило Container Queries: мы опрашиваем контейнер (родителя), но стилизуем его содержимое (детей). Сам контейнер внутри @container менять свои геометрические размеры (ширину, высоту, padding, влияющий на content-box) не должен. Если нужно изменить сам контейнер, оберни его в еще один внешний элемент и сделай контейнером именно его.

Ну что, теперь ты видишь, что медиа-запросы постепенно уходят на покой и остаются только для глобальных вещей вроде темной темы или базовой раскладки страницы? Пиши чистый, модульный CSS и не усложняй себе жизнь старыми хаками!

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

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

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

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