Адаптивные изображения и подписи на CSS: как работают container queries и :has()
Как создать адаптивный feature image с подписью без JavaScript? Разбираем, как работают container queries и селектор :has() в CSS, чтобы строить гибкие и живые компоненты под любой экран и контейнер.
2К открытий6К показов
Container queries и селектор :has() делают адаптивность вёрстки проще и чище. Разбираем, как с их помощью построить компонент с feature image, который подстраивается под контейнеры, меняет расположение и стиль подписи, оставаясь стабильным при любой ширине.
P.s. Это перевод англоязычного материала, но примеры и принципы легко применимы в ваших проектах.
Введем в курс дела
Когда автор оригинала переделывал сайт, ему понадобилось, чтобы feature image (картинка + подпись) адекватно вела себя в разных контейнерах и при разных размерах экрана.
Что было нужно:
- На маленьких размерах показывать подпись в классическом виде;
- Если контейнер достаточно большой, поворачивать изображение и показывать подпись по кругу в правом нижнем углу.
В демо без container queries это выглядело так:
В реальности, даже если контент уже вмещался в одну строку, фигура оставалась в классическом виде. Можно ли сделать лучше? Спойлер — да!
Сила container queries
Container queries позволяют переключать стили не в зависимости от вьюпорта, а от размера контейнера, в котором находится компонент.
В демо автор выделил четыре разных состояния размеров, чтобы показать, как с помощью container queries плавно поменять вид с «stacked» (вертикальная компоновка) на «circular» (круговая подпись) и обратно.
С media queries это превратилось бы в лес условий:
И всё это легко ломается, если вдруг меняется контент или макет.
Container queries же дают возможность адаптировать вид компонента в зависимости от реальной доступной ширины, без лишних хаков и постоянных правок брейкпоинтов при каждом изменении дизайна.
Как это собрать на практике
1. Оборачиваем компонент в контейнер
Чтобы container queries работали корректно, компонент нужно обернуть в отдельный контейнер и уже относительно него делать запросы. Иначе CSS будет «зацикливаться» и ломаться.
Определяем figure-wrapper как контейнер:
Простой тест: если ширина контейнера больше 240px, добавляем outline к figure.
Ресайзим окно браузера — и видим, как рамка появляется при ширине 240px+:
Условные стили — :has()
По умолчанию компонент в stacked-версии. Если ширины достаточно, переключаемся на circular.
Важно проверить, есть ли у figure — figcaption. Если есть — поворачиваем изображение. Для этого используем селектор :has().
Базовая структура готова, переходим к верстке.
2. Собираем лейаут
Хотя задача простая, есть несколько рабочих подходов.
Опция 1: Полный position:absolute
Здесь и изображение, и подпись выносятся из потока:
Но у такого решения контейнер почти не имеет высоты, так как внутри нет элементов в потоке.
Исправляем, задавая aspect-ratio и ширину контейнеру:
Работает, но автор оригинала не в восторге:
- много position: absolute;
- приходится задавать размеры картинкам через проценты, это ломает масштабирование.
Опция 2: CSS Grid с наложением
Здесь используем CSS Grid, чтобы накладывать изображение и подпись, размещая их в одной ячейке:
Результат:
Далее подгоняем размер изображения, уменьшая его на часть размера подписи:
Перед нами — аккуратный и гибкий лейаут, который хорошо работает и не требует хакинга.
Опция 3: Паддинги вместо абсолютов
В этом варианте position: absolute используется только для подписи, а для картинки задаются паддинги, чтобы она не накладывалась на подпись:
Автор оригинала выбрал этот вариант для своего блога, но отмечает, что и Grid ничуть не хуже — обе опции удобны и управляемы.
Шаг 3. Делаем компонент «жидким»
Чтобы компонент уверенно работал при любой ширине контейнера и экрана, можно добавить fluid CSS. Настраиваем «жидкость» у следующих параметров:
- скругления углов;
- размер шрифта;
- размер подписи;
- паддинги.
Благодаря единицам container query, можно адаптировать размеры под ширину контейнера. В данном случае используется cqw (container query width).
При изменении ширины контейнера меняются скругления, шрифт, паддинги и размер подписи. Так компонент становится адаптивным
Шаг 4. Тестируем в разных контекстах
Автор оригинала тестировал компонент в разных контекстах, чтобы убедиться в его стабильной работе. Параметры следующие:
- секция с двумя колонками;
- компонент на всю ширину;
- сетка с тремя колонками;
- сетка с двумя колонками, где первый элемент занимает 66% пространства;
- мобильный размер.
При изменении сеток и ширины компонент продолжает уверенно адаптироваться, не ломая макет.
Вывод
На первый взгляд компонент может показаться простым, но при использовании в разных контекстах появляются дополнительные вызовы. Современный CSS (container queries, :has(), cqw) позволяет элегантно решать такие задачи, избавляясь от хакинга и лишнего JS.
2К открытий6К показов













