CSS свойство contain

Источник: «The CSS contain property»
CSS Containment используется для оптимизации и открытия возможностей стилизации путём изоляции элементов от остальной части страницы. Различные значения contain (size, paint, layout и т. д.) обеспечивают различные преимущества и компромиссы.

Назначение CSS свойства contain (CSS Containment) двояко:

  1. Оптимизация
  2. Возможности стилизации

Когда мы применяем contain к элементу, мы изолируем его (и его потомков) от остальной части страницы, и эта изоляция открывает все возможности. Существуют различные типы изолирования, выполняющие разные задачи, и мы рассмотрим каждый из них.

.element {
contain: size;
contain: paint;
contain: layout;

/* также их можно комбинировать, например. */
contain: size layout;
}

Во-первых, оптимизация. Когда что-то изменяет элемент после рендеринга страницы, браузер переосмысливает всю страницу на случай, если этот элемент повлияет на остальную часть страницы (видимую или нет). Но при использовании содержащегося элемента мы сообщаем браузеру, что внесённое изменение касается только содержащегося элемента и его дочерних элементов. И браузеру не нужно беспокоиться об остальной части страницы, потому что на неё это никак не повлияет.

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

С появлением CSS Containment можно сделать гораздо больше относительных стилей в области видимости содержащегося элемента и его потомков. По ходу дела вы увидите примеры.

Сдерживание размера

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

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

Но фиксированный размер не в тренде. В наши дни существует множество вариантов динамического изменения размера. Например, CSS единицы относительно размера корневого шрифта (rem, rex и т. д.), единицы, реагирующие на размер области просмотра (vw, dvh и т. д.), единицы относительно текущего размера шрифта (em, lh и т. д.), и так далее. Это означает, что, как правило, мы неплохо справляемся с определением размеров различных элементов на странице для разных размеров экрана и контента.

Что если, пользователь взаимодействует со страницей и вызывает на ней появление новой динамической информации? Эта новая информация занимает место. Теперь у пользователя есть варианты и он может сделать выбор.

Если это похоже на последнее, то сдерживание размеров может стать решением (или частью решения).

.box {
width: 100px;
min-height: 100px;
img {
width: 200%;
...
}
&:nth-of-type(2) { /* второй бокс */
contain: size;
...
}
...
}

See the Pen

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

Сдерживание отрисовки

Если вы знакомы с CSS свойством overflow, это хорошее начало для понимания сдерживания отрисовки. Однако это не совсем одно и то же.

За пределами сдерживания отрисовки бокса элемента, браузер не отображает контент и не даёт его прокручивать никакими способами. В этом аспекте поведение сдерживания отрисовки похоже на overflow: clip, а не на overflow: hidden (позволяющего прокручивать скрытое содержимое или элементы с помощью методов, подобных JavaScript событию scroll).

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

Есть и ещё одна веская причина, по которой может понадобиться сдерживания отрисовки.

Как уже говорилось в начале статьи, сдерживание — это изоляция элемента от всех факторов. Здесь это стоит повторить. Сдерживание отрисовки — это не только вырезание того, что выпало за пределы бокса контейнера, но и изоляция самого бокса от остальной части отрисованной страницы путём создания нового размещения и форматирования контекста для этого элемента. Сдерживание отрисовки также генерирует отдельное абсолютное и фиксированное позиционирование бокса контейнер (это объясняется в разделе Сдерживание компоновки).

Ниже приведены два примера: первый — пример сдерживания отрисовки(contain: paint), а второй — сравнение поведения overflow: clip и contain: paint. Во втором примере хорошо виден изолирующий эффект сдерживания краски, когда на сдерживаемый элемент не влияет CSS-смешивание, применённое к его родственному элементу.

.box {
width: 100px;
img {
width: 200%;
...
}
&:nth-of-type(2) { /* второй бокс */
contain: paint;
...
}
...
}

See the Pen

section {
div {
width: 100px;
aspect-ratio: 1/1;
}
.box {
background: red;
}
&:nth-of-type(2) .box {
overflow: clip;
}
&:nth-of-type(3) .box {
contain: paint;
}
.box-sibling {
background: blue;
mix-blend-mode: hue;
...
}
}

See the Pen

Сдерживание компоновки

Макет — это, по сути, поток элементов и контента. На протяжении многих лет помимо изменения размеров, помимо рисования, большую часть работы в области вёрстки мы делегировали браузерам. Существуют CSS свойства, такие как float, vertical-align и другие, позволяющие нам сообщать браузерам, где мы предпочитаем немного изменить положение элемента по сравнению с его естественным местом на странице.

Кроме того, существуют полномасштабные макеты, такие как Grid Layout, Page Layout (используется для печати), Column Layout и т. д., позволяющие браузеру разместить всё на странице в соответствии с нашими предпочтениями.

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

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

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

.box {
width: 100px;
aspect-ratio: 1/1;
.fixed-element {
background: lime;
position: fixed;
left: 0px;
bottom: 0px;
...
}
&:nth-of-type(2) { /* Бокс B */
contain: layout;
...
}
...
}

See the Pen

Сдерживание инлайн размера и стиля

Хотя они ещё не являются рекомендацией W3C, и contain: inline-size, и contain: style — это допустимые значения, хорошо поддерживаемые браузерами и включённые в рабочие проекты W3C по модулю CSS Containment Module Level 2 и 3. Они не упомянуты в начале статьи только потому, что ещё не приобрели статус рекомендаций.

Функции сдерживания стиля в настоящее время также несколько условны и могут расшириться, прежде чем они получат статус рекомендации W3C.

Тем не менее кратко объясню их оба. Сдерживание инлайн размера — это то же самое, что и сдерживание размера, но только для инлайн размеров (направление горизонтали/ширины в любом горизонтальном режиме записи слева направо или справа налево). Это позволяет ограничить размеры элементов вдоль их инлайн осей. Это особенно характерно для контейнерных запросов. Здесь не упоминались контейнерные запросы, но концептуально эти вещи связаны. Когда вы задаёте тип контейнера: inline-size, как это требуется для типичных контейнерных запросов, вы фактически также неявно задаёте contain: inline-size.

Когда элемент имеет функцию сдерживание стиля, подсчёт CSS счётчиков (CSS Counter) и значений quotes свойства content внутри содержащегося элемента не зависит от значений счётчиков и кавычек, указанных снаружи. По сути, счётчики и кавычки находятся в пределах ограничивающего стиль элемента. Довольно интересно!

Значения strict и content

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

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

Есть ещё значение content, представляющее собой комбинацию paint, layout и style. Скорее всего, вам захочется использовать это значение, если ваша цель — просто обеспечить, чтобы ничто не выходило за границы элемента любой ценой, или чтобы браузер не отрисовывал и не выкладывал содержащиеся элементы и их дочерние элементы, когда они находятся за пределами экрана или скрыты, в целях оптимизации.

Таковы мои рекомендации по использованию CSS свойства contain. Это свойство, о котором стоит узнать как для изучения методов программирования, так и для оптимизации веб-страниц.

Ссылки

Дополнительные материалы

Предыдущая Статья

Новые функции массива в PHP 8.4

Следующая Статья

PHP 8.4 Property Hooks (хуки свойств)