24.09.2021

Контейнерные запросы CSS: примеры использования и стратегии миграции

Контейнерные запросы CSS: примеры использования и стратегии передвижения

От создателя: контейнерные запросы CSS приближают медиа-запросы к мотивированным элементам и позволяют им адаптироваться фактически к любому заданному контейнеру или макету. В этой статье мы собираемся поведать об основах контейнерных запросов CSS и о том, как их использовать сейчас.

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

Контейнерные запросы CSS: примеры использования и стратегии передвижения

Пример адаптивного макета странички. На левом изображении показан макет рабочего стола с шириной области просмотра 1280 пикселей, а на правом изображении — мобильный макет с шириной области просмотра 568 пикселей.

Но адаптивный веб-дизайн (RWD) не ограничивается макетом странички — отдельные компоненты пользовательского интерфейса обычно имеют медиа-запросы, которые имеют возможность изменять свой стиль в зависимости от размеров области просмотра.

Контейнерные запросы CSS: примеры использования и стратегии передвижения

Пример адаптивного компонента карточного макета. На левом изображении показан компонент с шириной области просмотра 720 пикселей, а на правом изображении показан макет компонента с шириной области просмотра 568 пикселей.

Может быть, вы уже заметили проблему с предшествующим утверждением — макет отдельных компонентов пользовательского интерфейса нередко не зависит исключительно от размеров области просмотра. В то время как макет странички — это элемент, тесно связанный с размерами области просмотра и один из самых верхних частей в HTML, компоненты пользовательского интерфейса имеют возможность использоваться в разных контекстах и контейнерах. Если задуматься, область просмотра — это просто контейнер, а составляющие пользовательского интерфейса могут быть вложены в другие контейнеры со стилями, которые оказывают влияние на размеры и макет компонента.

Контейнерные запросы CSS: примеры использования и стратегии передвижения

Пример макета странички с одним и тем же компонентом пользовательского интерфейса карточного макета в сетке из 3-х столбцов верхнего раздела и списке нижнего раздела.

Невзирая на то, что один и тот же компонент карточки продукта употребляется как в верхней, так и в нижней частях, стили компонент зависят не только от размеров области просмотра, но и от контекста и CSS параметров контейнера (например, сетки в примере), где он расположен.

Конечно, мы можем структурировать наш CSS, с поддержкой вариантов стилей для различных контекстов и контейнеров, чтобы вручную разрешить проблему макета. В худшем случае этот вариант будет добавлен с переопределением стиля, что приведет к дублированию кода и неким специфичным проблемам.

CSS

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

Контейнерные запросы CSS: примеры использования и стратегии передвижения

Пример того, как медиа-запрос нельзя накрепко связать с размерами элемента. Различные характеристики CSS могут влиять на размеры элемента в контейнере. В этом примере наполнение контейнера между двумя изображениями различается.

В последующем примере демонстрируется именно эта проблема — даже невзирая на то, что был реализован отзывчивый элемент карточного макета и он отлично выглядит в стандартном варианте использования, но он смотрится плохо, если перемещен в другой контейнер со качествами CSS, которые влияют на размеры элемента.

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

Это одна из заморочек, которые контейнерные запросы пытаются исправить. Контейнерные запросы расширяют функциональность имеющихся медиа-запросов с помощью запросов, которые зависят от размеров мотивированного элемента. Этот подход дает три главных преимущества:

Стили контейнерных запросов используются в зависимости от размеров самого мотивированного элемента. Компоненты пользовательского интерфейса смогут приспособиться к любому заданному контексту или контейнеру.

Разработчикам не необходимо искать значение «магического числа» измерения области просмотра, которое связывает медиа-запрос области просмотра с мотивированным измерением компонента пользовательского интерфейса в определенном контейнере или конкретном контексте.

Нет необходимости добавлять дополнительные классы CSS либо медиа-запросы для разных контекстов и вариантов использования.

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

Помощь браузерами

Контейнерные запросы — это экспериментальная функция, доступная в текущее время в версии Chrome Canary (на момент написания этой статьи). Если вы желаете продолжить и запустить примеры с CodePen в этой статье, вам нужно включить контейнерные запросы в следующем URL-адресе опций.

Контейнерные запросы CSS: примеры использования и стратегии передвижения

Если вы используете браузер, который не поддерживает контейнерные запросы, совместно с демонстрацией CodePen будет предоставлено изображение, демонстрирующее предполагаемый рабочий пример.

Работа с контейнерными запросами

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

Свойство сontain

Свойство CSS сontain было добавлено в большая часть современных браузеров и на момент написания этой статьи и имело благопристойную поддержку браузеров на уровне 75%. Свойство сontain употребляется в основном для оптимизации производительности, указывая браузеру, какие части страничек могут рассматриваться как независимые и не будут оказывать влияние на изменения других элементов в дереве. Таким образом, если изменение происходит в одном элементе, браузер опять отобразит только эту часть (поддерево), а не всю страничку. При использовании свойства сontain, мы можем указать, какие типы ограничений мы желаем использовать — layout, size или paint.

Есть много восхитительных статей о свойстве сontain, в которых более тщательно описаны доступные варианты и варианты использования, потому я собираюсь сосредоточиться только на свойствах, связанных с контейнерными запросами.

Какое отношение имеет свойство CSS сontain, применяемое для оптимизации, к контейнерным запросам? Для работы контейнерных запросов браузеру нужно знать, происходит ли изменение в макете дочерних частей элемента, и он должен повторно показывать только этот компонент. Браузер будет знать, что необходимо применить код в контейнерном запросе к соответственному компоненту, когда компонент визуализируется или его размер меняется.

Мы будем использовать значения layout и style для характеристики contain, но мы также будем нуждаться в дополнительном значении, которое говорит браузеру об оси, в которой будут происходить изменение.

inline-size — Ограничение на интегрированной оси. Ожидается, что это значение будет иметь существенно больше вариантов использования, поэтому оно реализуется в первую очередь.

block-size — Ограничение на оси блока. Оно все еще находится в разработке и в текущее время недоступен.

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

CSS

Обратите внимание на то, что мы не добавляем это значение к более удаленному родительскому элементу section и не сохраняем контейнер как можно поближе к затронутому элементу.

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

Контейнерный запрос

После того, как было добавлено свойство contain, мы можем написать контейнерный запрос. Мы добавили свойство contain к элементу с классом card, потому теперь мы можем включить любой из его дочерних частей в контейнерный запрос.

Как и в случае с обыкновенными медиа-запросами, нам нужно определить запрос, используя характеристики min-width или max-width и поместить все селекторы снутри блока. Однако мы будем использовать ключевое слово @container заместо определения контейнерного запроса с помощью @media.

CSS

И card__wrapper и card__image элементы являются наследниками элемента card, который имеет свойство contain. Когда мы заменим обыденные медиа-запросы контейнерными запросами, удалим дополнительные классы CSS и запустим пример CodePen в браузере, который поддерживает контейнерные запросы, мы получаем последующий результат.

Контейнерные запросы CSS: примеры использования и стратегии передвижения

В этом примере мы изменяем размер не области просмотра, а самого элемента контейнера
, к которому использовано свойство CSS resize. Компонент автоматически переключается меж макетами в зависимости от размеров контейнера.

Обратите внимание, что контейнерные запросы в текущее время не отображаются в инструментах разработчика Chrome, что затрудняет отладку контейнерных запросов. Ожидается, что в будущем в браузер будет добавлена соответственная поддержка отладки.

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

Прогрессивное улучшение

Давайте поглядим, сможем ли мы добавить альтернативу варианту класса CSS и медиа-запросам. Мы можем использовать запросы функций CSS с правилом @supports для обнаружения доступных функций браузера. Но мы не можем проверить другие запросы, потому нам нужно добавить проверку на contain:layout inline-size style. Придется представить, что браузеры, поддерживающие свойства inline-size, также поддерживают контейнерные запросы.

CSS

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

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

В качестве кандидатуры вы можете использовать полифилы. Я желал бы выделить два полифила JavaScript, которые в текущее время активно поддерживаются и предоставляют нужные функции контейнерных запросов:

cqfill Джонатана Нила — Полифилл JavaScript для CSS и PostCSS

react-container-query Криса Гарсиа — Пользовательский хук и компонент для React

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

Если вы решите воплотить контейнерные запросы в существующем проекте, который употребляет медиа-запросы, вам потребуется реорганизовать код HTML и CSS. Я нашел, что это самый быстрый и обычной способ добавления контейнерных запросов, обеспечивающий надежную связь с медиа-запросами. Давайте поглядим на предыдущий пример.

CSS

Поначалу обернем корневой HTML-элемент, к которому использован медиа-запрос, элементом, имеющим свойство contain.

CSS

Потом, обернем медиа-запрос в запрос функции и добавим контейнерный запрос.

CSS

Несмотря на то что этот метод приводит к некоторому раздуванию и дублированию кода, с помощью SASS либо PostCSS вы можете избежать дублирования, потому исходный код CSS остается поддерживаемым.

Как только контейнерные запросы получат соответствующую поддержку браузера, вы можете рассмотреть возможность удаления блоков кода @supports not (contain: inline-size) и продолжение поддержки только контейнерных запросов.
Стефани Эклз не так давно опубликовала отличную статью о контейнерных запросах, охватывающую разные стратегии миграции. Я рекомендую ознакомиться с ней для получения дополнительной инфы по теме.

Сценарии вариантов использования

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

Другие примеры по теме (для примеров требуется браузер, поддерживающий контейнерные запросы):

Модульные составляющие, такие как карточки, элементы форм, баннеры и т. д.

Адаптируемые макеты

Пагинация с различными функциями для мобильных и настольных ПК

Радостные эксперименты с изменением размера CSS

Заключение

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

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

По материалам webformyself.com

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *