Медиа- и контейнерные запросы — Примеры

Пример 1 — Правила от настольного вида, которые обязаны себя отменять

Таблица стилей начинается с широкой раскладки и снимает её слой за слоем запросами max-width; двум правилам теперь требуется !important. Скажите, почему файл растёт, затем перепишите запросы, начиная с узкой раскладки.

<div class="grid">
  <article>Один</article>
  <article>Два</article>
</div>
.grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1rem; }

@media (max-width: 60rem) {
  .grid { grid-template-columns: 1fr 1fr; }        /* отменить три столбца */
}
@media (max-width: 40rem) {
  .grid { grid-template-columns: 1fr !important; } /* отменить два */
}

Решение

.grid { display: grid; grid-template-columns: 1fr; gap: 1rem; }

/* два столбца перестают помещаться ниже 40rem */
@media (min-width: 40rem) { .grid { grid-template-columns: 1fr 1fr; } }
/* третий столбец начинает переполняться ниже 60rem */
@media (min-width: 60rem) { .grid { grid-template-columns: 1fr 1fr 1fr; } }

Версия с max-width обязана отменять широкое объявление на каждом шаге, поэтому специфичность подрастает и появляется !important — а это симптом, а не исправление. Однако основа листа на узкой раскладке и добавление возможностей через min-width означают, что каждый запрос только добавляет, порядок каскада совпадает с порядком чтения, и ни одно правило не нужно переопределять. Точки перелома тоже написаны там, где раскладка действительно ломается, а не по списку устройств, поэтому комментарий рядом с каждой объясняет, зачем она есть. На окне 320px помещается один столбец; выше 640px — два; выше 960px — три.

Пример 2 — Контейнерный запрос, который никогда не срабатывает

Компонент-карточка стоит в широкой основной колонке и в узкой боковой панели; компактный стиль написан как контейнерный запрос, но боковая панель продолжает отрисовывать широкую раскладку. Найдите, чего не хватает, затем исправьте это.

<aside class="sidebar"><div class="card-grid"><article class="card">…</article></div></aside>
.card { display: grid; grid-template-columns: 8rem 1fr; gap: 1rem; }

@container cards (max-width: 30rem) {
  .card { grid-template-columns: 1fr; }   /* никогда не применяется */
}

Решение

.card-grid { container-type: inline-size; container-name: cards; }

.card { display: grid; grid-template-columns: 8rem 1fr; gap: 1rem; }

@container cards (max-width: 30rem) {
  .card { grid-template-columns: 1fr; }
}

Контейнерному запросу нужен зарегистрированный предок, о котором спрашивать, а без container-type его нет, поэтому правило молча никогда не срабатывает. Объявление обёртки контекстом сдерживания даёт ему имя, и карточка затем отвечает на ширину, которую действительно получает: в боковой панели 240px вычисленная раскладка — один столбец, а в основной колонке 900px остаётся два. В этом и смысл запроса к контейнеру, а не к окну. Один и тот же компонент корректно адаптируется в обоих местах.