Долгое время медиазапросы были основой адаптивной вёрстки. Если для элемента дизайна не хватало места и разработчику надо было его скрыть, скорее всего писалось что-то подобное:
.input__icon { display: none;}@media (min-width: 580px) { .input__icon { display: block; width: 32px; height: 32px; }}
.input__icon { display: none; } @media (min-width: 580px) { .input__icon { display: block; width: 32px; height: 32px; } }
Такой код работает, но с нюансом. Если доступного пространства под элемент станет больше, а ширина области просмотра останется прежней — иконка по-прежнему будет скрыта. Было бы круто отвязаться от области просмотра и получить поведение, при котором внешний вид компонента будет меняться в зависимости от доступного для него пространства.
Здесь и приходят на помощь выражения от контейнера. Они позволяют автоматически менять внешний вид компонента в зависимости от стилей родителя. Чтобы начать использовать выражения от контейнер надо сначала объявить родитель компонента контейнером с помощью свойства container
:
.form__item { container-type: inline-size;}
.form__item { container-type: inline-size; }
У container
есть три значения:
normal
— значение по умолчанию. Создаёт контейнер, который не позволяет запрашивать размеры, но разрешает запрос стилей.inline
— создаёт контейнер, который позволяет запрашивать размер по строчному направлению оси.- size size
— создаёт контейнер, который позволяет запрашивать размер по любой оси: и строчной, и блочной.
При объявлении контейнера с помощью container
под капотом автоматически создаётся контекст, при котором дочерний компонент перестаёт влиять на элементы за пределами своего контейнера.
Рекомендуется давать контейнерам имена с помощью свойства container
:
.form__item { container-type: inline-size; container-name: form-item;}
.form__item { container-type: inline-size; container-name: form-item; }
Так вы сможете обращаться к конкретному контейнеру, если их будет несколько. Для объявления контейнера с именем можно использовать и сокращённую запись:
.form__item { container: form-item / inline-size;}
.form__item { container: form-item / inline-size; }
Когда контейнер объявлен, появляется возможность обращаться к его стилям и использовать новые единицы измерений зависящие от размеров контейнера:
cqw
— 1% от ширины контейнера.cqh
— 1% от высоты контейнера.cqi
— 1% отinline
контейнера.- size cqb
— 1% отblock
контейнера.- size cqmin
— меньшее изcqi
иcqb
.cqmax
— большее изcqi
иcqb
.
Синтаксис запроса к контейнеру во многом похож на медиавыражения, но вместо директивы @media
используется @container
:
@container (inline-size >= 300px) { .input__icon { /* Изменение стилей компонента */ }}
@container (inline-size >= 300px) { .input__icon { /* Изменение стилей компонента */ } }
Можно запрашивать не только размеры контейнера, а любые его вычисленные стили. Для этого используется функция style
.
@container style([свойство]: [значение свойства]) { /* Новые стили */}
@container style([свойство]: [значение свойства]) { /* Новые стили */ }
Как и в случае с медиавыражениями, можно комбинировать запросы с помощью логических операторов:
@container (inline-size >= 300px) and style(--bg-color: #fff) { /* Новые стили */}
@container (inline-size >= 300px) and style(--bg-color: #fff) { /* Новые стили */ }
Или даже вкладывать контейнеры друг в друга и обращаться к стилям контейнера, находящегося на несколько уровней выше. Для этого нужно дать контейнерам имена и обратиться к контейнеру по имени:
.form__item { container-type: inline-size; container-name: form-item;}.input { container-type: inline-size; container-name: input;}.input__icon { /* стили иконки поля ввода */}@container form-item (inline-size >= 300px) { .input__icon { /* изменение стилей */ }}
.form__item { container-type: inline-size; container-name: form-item; } .input { container-type: inline-size; container-name: input; } .input__icon { /* стили иконки поля ввода */ } @container form-item (inline-size >= 300px) { .input__icon { /* изменение стилей */ } }
При запросе к конкретному контейнеру — стили применятся, если компонент находится именно в нём. Если не указывать имя контейнера, возьмётся ближайший, а если такового нет, выражение от контейнера не будет работать.