Запросы CSS-контейнеров все еще набирают обороты, и многие из нас замочат с ними руки, даже если это для небольших экспериментов или чего-то еще. У них есть большой, но не совсем полный, поддержка браузера — достаточно, чтобы оправдать их использование в некоторых проектах, но, возможно, не до такой степени, чтобы у нас возник соблазн начать замену медиа-запросы из прошлых проектов с блестящими новыми запросами размера контейнера.
Хотя они, безусловно, удобны! На самом деле, я уже сталкивался с несколькими ситуациями, когда я действительно хотел получить их, но просто не мог преодолеть требования поддержки. Если бы я мог их использовать, вот как это выглядело бы в тех ситуациях.
На момент написания этой статьи все следующие демонстрации лучше всего просматривать в Chrome или Safari. Firefox планирует поддержка корабля в версии 109.
Случай 1: сетка карт
Вы как бы должны были ожидать этого, не так ли? Это настолько распространенная модель, что все мы, кажется, сталкиваемся с ней в какой-то момент. Но дело в том, что запросы размера контейнера позволили бы мне значительно сэкономить время и получить лучший результат, если бы я мог использовать их вместо стандартных медиазапросов.
Допустим, вам поручили построить эту сетку карточек с требованием, чтобы каждая карточка сохраняла соотношение сторон 1:1:
Это сложнее, чем кажется! Проблема в том, что определение размера содержимого компонента по ширине окна просмотра оставляет вас во власти того, как компонент реагирует на окно просмотра, а также как реагируют на него любые другие контейнеры-предки. Если, например, вы хотите, чтобы размер шрифта заголовка карты уменьшался, когда карта достигает определенного встроенного размера, нет надежного способа сделать это.
Вы можете установить размер шрифта в vw
единиц, я полагаю, но компонент по-прежнему привязан к ширине области просмотра браузера. И это может вызвать проблемы, когда сетка карт используется в других контекстах, которые могут не иметь одинаковых точек останова.
В моем реальном проекте я остановился на подходе JavaScript, который:
- Прослушивание события изменения размера.
- Рассчитайте ширину каждой карты.
- Добавьте встроенный размер шрифта к каждой карточке в зависимости от ее ширины.
- Стилизуйте все внутри, используя
em
единиц.
Кажется, много работы, верно? Но это стабильное решение для получения необходимого масштабирования на разных размерах экрана в разных контекстах.
Контейнерные запросы были бы намного лучше, потому что они предоставляют нам блоки запроса контейнера, такой как cqw
Ед. изм. Вы, наверное, уже поняли, но 1cqw
равно 1%
ширины контейнера. У нас также есть cqi
единица, которая является мерой встроенной ширины контейнера, и cqb
для ширины блока контейнера. Итак, если у нас есть контейнер для карт, который 500px
широкий, а 50cqw
значение вычисляется до 250px
.
Если бы я мог использовать контейнерные запросы в своей сетке карточек, я мог бы настроить .card
компонент как контейнер:
.card {
container: card / size;
}
Тогда я мог бы установить внутреннюю оболочку с padding
масштабируется на 10%
.card
ширина с помощью cqw
Блок:
.card__inner {
padding: 10cqw;
}
Это хороший способ последовательно масштабировать расстояние между краями карты и ее содержимым, независимо от того, где карта используется при любой заданной ширине области просмотра. Медиа-запросы не требуются!
Еще одна идея? Использовать cqw
единиц для размера шрифта внутреннего содержимого, затем примените отступы в em
единицы:
.card__inner {
font-size: 5cqw;
padding: 2em;
}
5cqw
— произвольное значение — именно то, на котором я остановился. Это заполнение по-прежнему равно 10cqw
С em
единица относится к .card__inner
размер шрифта!
Вы уловили это? 2em
относительно 5cqw
установленный размер шрифта на том же контейнере. Контейнеры работают не так, как мы привыкли, т.к. em
единицы относятся к одному и тому же элементу font-size value
. Но я быстро заметил, что контейнерные блоки запросов относятся к ближайший родитель, который также является контейнером.
Например, 5cqw
не масштабируется на основе .card
ширина элемента в этом примере:
.card {
container: card / size;
container-name: card;
font-size: 5cqw;
}
Скорее, он масштабируется до любого ближайшего родителя, определенного как контейнер. Вот почему я создал .card__inner
обертка.
Случай 2: чередование макетов
Мне нужен был еще один карточный компонент в другом проекте. На этот раз мне нужно было, чтобы карта переходила из альбомной раскладки в портретную… затем обратно в альбомную и снова обратно в портретную, когда экран становится меньше.
Я проделал грязную работу по переводу этого компонента в портретную ориентацию в этих двух конкретных диапазонах области просмотра (привет новый синтаксис диапазона медиа-запросов!), но опять же, проблема в том, что он затем блокируется для заданных для него медиа-запросов, его родителя и всего остального, что может реагировать на ширину области просмотра. Нам нужно что-то, что работает в любых условиях, не беспокоясь о том, где контент сломается!
Запросы контейнеров облегчили бы эту задачу благодаря @container
править:
.info-card {
container-type: inline-size;
container-name: info-card;
}
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
Один запрос, бесконечная текучесть:
Но держись! Есть кое-что, на что вы, возможно, захотите обратить внимание. В частности, может быть сложно использовать подобный контейнерный запрос в системе дизайна на основе реквизита. Например, это .info-card
component может содержать дочерние компоненты, которые полагаются на реквизиты для изменения своего внешнего вида.
Почему это так важно? Книжный макет карты может потребовать альтернативного стиля, но вы не можете изменить реквизиты JavaScript с помощью CSS. Таким образом, вы рискуете дублировать требуемые стили. Я действительно коснулся этого и как это обойти в другой статье. Если вам нужно использовать запросы-контейнеры для значительного количества стилей, вам может понадобиться построить всю систему дизайна вокруг них, а не пытаться впихнуть их в существующую систему дизайна, которая перегружена медиа-запросами.
Случай 3: штрихи SVG
Вот еще один очень распространенный шаблон, который я недавно использовал, когда запросы размера контейнера привели бы к более отточенному продукту. Скажем, у вас есть значок, заблокированный с заголовком:
Heading
Довольно просто масштабировать значок с размером заголовка, даже без медиа-запросов. Проблема, однако, в том, что SVG stroke-width
может стать слишком тонким, чтобы быть заметным в меньшем размере, и, возможно, привлечь слишком много внимания сверхтолстым штрихом в большем размере.
Мне приходилось создавать и применять классы к каждому экземпляру значка, чтобы определить его размер и ширину штриха. Думаю, это нормально, если значок находится рядом с заголовком с фиксированным размером шрифта, но это не так хорошо при работе с плавным шрифтом, который постоянно меняется.
Размер шрифта заголовка может быть основан на ширине области просмотра, поэтому значок SVG необходимо настроить соответствующим образом, чтобы его штрих работал при любом размере. Вы можете сделать ширину штриха относительно заголовка font-size
установив его в em
единицы. Но если у вас есть определенный набор размеров обводки, которого вам нужно придерживаться, то это не сработает, потому что в противном случае масштабирование будет линейным — нет возможности настроить его на конкретный размер. stroke-width
значение в определенных точках, не прибегая к медиа-запросам по ширине области просмотра.
Но вот что бы я сделал, если бы в то время у меня была роскошь контейнерных запросов:
.icon {
container: icon / size;
width: 1em;
height: 1em;
}
.icon svg {
width: 100%;
height: 100%;
fill: none;
stroke: #ccc;
stroke-width: 0.8;
}
@container icon (max-width: 70px) {
.icon svg {
stroke-width: 1.5;
}
}
@container icon (max-width: 35px) {
.icon svg {
stroke-width: 3;
}
}
Сравните реализации и посмотрите, как версия запроса контейнера привязывает обводку SVG к определенной ширине, которую я хочу, исходя из ширины контейнера.
Бонус: другие типы запросов размера контейнера
Хорошо, так что я на самом деле не сталкивался с этим в реальном проекте. Но когда я просматривал информацию о запросах контейнеров, я заметил, что есть дополнительные вещи, которые мы можем запрашивать в контейнере, связанные с размером или физическими размерами контейнера.
Большинство примеров, которые я видел, запрашивают width
, max-width
и min-width
, height
, block-size
и inline-size
как я делал на протяжении всей этой статьи.
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
Но MDN описывает еще две вещи мы можем запросить против. Один orientation
что имеет смысл, потому что мы постоянно используем его в медиа-запросах. Это ничем не отличается от контейнерных запросов:
@media screen (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
@container info-card (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
Другой? Это aspect-ratio
, хочешь верь, хочешь нет:
@container info-card (aspect-ratio: 3/2) {
.info-card__inner {
/* Style away! */
}
}
Вот редактируемая демонстрация, чтобы поиграть с обоими примерами:
Я еще не нашел хорошего варианта использования ни для одного из них. Если у вас есть какие-либо идеи или вы чувствуете, что это могло бы помочь вам в ваших проектах, дайте мне знать в комментариях!