Помощь браузерам в оптимизации с помощью свойства CSS Contain
Опубликовано: 2022-03-10contain
CSS contains дает вам способ объяснить ваш макет браузеру, чтобы можно было оптимизировать производительность. Тем не менее, это имеет некоторые побочные эффекты с точки зрения вашего макета. В этой статье я собираюсь представить спецификацию CSS, которая только что стала рекомендацией W3C. Спецификация включения CSS определяет одно свойство, contain
, и оно может помочь вам объяснить браузеру, какие части вашего макета независимы и не потребуют пересчета, если какая-то другая часть макета изменится.
Хотя это свойство существует для оптимизации производительности, оно также может повлиять на макет вашей страницы. Поэтому в этой статье я объясню различные типы сдерживания, от которых вы можете извлечь выгоду, а также то, на что вам нужно обратить внимание, применяя contain
к элементам на вашем сайте.
Проблема пересчета макета
Если вы создаете простые веб-страницы, элементы которых не добавляются и не изменяются динамически после их загрузки с помощью JavaScript, вам не нужно беспокоиться о проблеме, которую решает сдерживание CSS. Браузер должен вычислить ваш макет только один раз, когда страница загружается.
Где Containment становится полезным, когда вы хотите добавить элементы на свою страницу без необходимости перезагрузки пользователем. В моем примере я создал большой список событий. Если вы нажмете кнопку, первое событие будет изменено, добавлен плавающий элемент и изменен текст:

Когда содержимое нашего блока изменяется, браузер должен учитывать, что любой из элементов мог измениться. Браузеры, как правило, довольно хорошо справляются с этим, так как это обычное дело. Тем не менее, как разработчик, вы будете знать, является ли каждый из компонентов независимым, и что изменение одного из них не влияет на другие, поэтому было бы неплохо, если бы вы могли сообщить об этом браузеру через свой CSS. Это то, что дает вам включение и свойство CSS contain
.
Как сдерживание помогает?
HTML-документ представляет собой древовидную структуру, которую вы можете увидеть при проверке любого элемента с помощью DevTools. В приведенном выше примере я определяю один элемент, который хочу изменить с помощью JavaScript, а затем вношу некоторые изменения во внутренние компоненты. (Это означает, что я изменяю вещи только внутри поддерева для этого элемента списка.)

Применение свойства contain
к элементу сообщает браузеру, что изменения относятся к поддереву этого элемента, так что браузер может выполнить любую возможную оптимизацию, зная, что ничего за пределами этого элемента не изменится. Что именно может делать конкретный браузер, зависит от движка. Свойство CSS просто дает вам — как разработчику и эксперту по этому макету — возможность сообщить об этом.
Во многих случаях вы можете сразу же начать использовать свойство contains, однако разные значения contain
некоторые потенциальные побочные эффекты, которые стоит понять, прежде чем добавлять свойство к элементам на вашем сайте.
Использование сдерживания
Свойство contain
может устанавливать три различных типа содержания:
-
layout
-
paint
-
size
Примечание . В спецификации уровня 2 есть значение style
. Он был удален с уровня 1, поэтому не отображается в Рекомендации и не реализован в Firefox.
Макет
Сдерживание макета приносит самые большие преимущества. Чтобы включить сдерживание макета, используйте следующий фрагмент кода:
.item { contain: layout; }
Когда включено включение макета, браузер знает, что ничто за пределами элемента не может повлиять на внутренний макет, и ничто внутри элемента не может ничего изменить в макете вещей за его пределами. Это означает, что он может сделать любые возможные оптимизации для этого сценария.
Несколько дополнительных вещей происходят, когда включено сдерживание макета. Все это гарантирует, что этот блок и его содержимое не зависят от остальной части дерева.
Поле устанавливает независимый контекст форматирования . Это гарантирует, что содержимое блока останется в блоке — в частности, плавающие элементы будут содержаться, а поля не будут схлопываться через блок. Это то же самое поведение, которое мы включаем, когда используем display: flow-root
, как описано в моей статье «Понимание макета CSS и контекста форматирования блоков». Если поплавок может высовываться из вашей коробки, заставляя следующий текст обтекать поплавок, это будет ситуация, когда элемент меняет расположение вещей за его пределами, что делает его плохим кандидатом для сдерживания.
Содержащий блок действует как содержащий блок для любых потомков с абсолютной или фиксированной позицией. Это означает, что он будет действовать так, как если бы вы использовали position: relative
в поле, которое вы применили, contain: layout
.
Коробка также создает контекст стека . Поэтому z-index
будет работать с этим элементом, его дочерние элементы будут складываться на основе этого нового контекста.
Если мы посмотрим на пример, на этот раз с contain: layout
, вы увидите, что при введении плавающего элемента он больше не выступает из нижней части блока. Это наш новый контекст форматирования блока в действии, содержащий число с плавающей запятой.

Краска
Чтобы включить сдерживание краски, используйте следующее:

.item { contain: paint; }
При включенном сдерживании рисования возникают те же побочные эффекты, что и при сдерживании макета: содержащий блок становится независимым контекстом форматирования, содержащим блоком для позиционированных элементов и устанавливает контекст наложения.
Что делает сдерживание краски, так это указывает браузеру, что элементы внутри содержащего блока не будут видны за пределами этого блока. Содержимое по существу будет обрезано до поля.
Мы можем увидеть, как это происходит на простом примере. Даже если мы задаем нашей карточке высоту, плавающий элемент все равно выпирает из нижней части коробки из-за того, что плавающий объект выведен из потока.

При включенном сдерживании краски плавающий элемент теперь обрезается до размера коробки. Ничто не может быть закрашено за пределы элемента с примененным contain: paint
.

Размер
Сдерживание размера — это значение, которое, скорее всего, вызовет у вас проблемы, если вы не полностью понимаете, как оно работает. Чтобы применить сдерживание размера, используйте:
.item { contain: size; }
Если вы используете сдерживание размера, вы сообщаете браузеру, что знаете размер блока, и он не изменится. Это означает, что если у вас есть блок с автоматическим изменением размера в блочном измерении, он будет рассматриваться так, как если бы содержимое не имело размера, поэтому блок схлопнется, как если бы у него не было содержимого.
В приведенном ниже примере я не указал высоту li
; они также contain: size
применяется. Вы можете видеть, что все элементы свернуты, как будто у них вообще нет содержимого, что делает список очень странным!

Если вы зададите полям высоту, то высота будет учитываться при использовании contain: size
. Само по себе сдерживание размера не создаст новый контекст форматирования и, следовательно, не будет содержать плавающие элементы и поля, в отличие от сдерживания макета и рисования. Маловероятно, что вы будете использовать его в одиночку; вместо этого, скорее всего, вы примените его вместе с другими значениями contain
, чтобы иметь возможность получить максимально возможное сдерживание.
Сокращенные значения
В большинстве случаев вы можете использовать одно из двух сокращенных значений, чтобы получить максимальную отдачу от сдерживания. Чтобы включить компоновку и сдерживание рисования, используйте contain: content;
, и чтобы включить все возможные ограничения (имея в виду, что элементы, у которых нет размера, затем будут свернуты), используйте contain: strict
.
Спецификация говорит:
«contain: content
достаточно «безопасен» для широкого применения; его эффекты на практике довольно незначительны, и большая часть контента не будет противоречить его ограничениям. Однако, поскольку он не применяет сдерживание размера, элемент по-прежнему может реагировать на размер своего содержимого, что может привести к просачиванию недействительного макета дальше по дереву, чем хотелось бы. По возможности используйтеcontain: strict
, чтобы получить как можно больше сдерживания».
Поэтому, если вы не знаете заранее размер элементов и понимаете, что float и margin будут содержаться, используйте contain: content
. Если вы знаете размер элементов в дополнение к другим побочным эффектам сдерживания, используйте contain: strict
. Остальное зависит от браузера, вы внесли свою лепту, объяснив, как работает ваш макет.
Могу ли я использовать сдерживание сейчас?
Спецификация CSS Containment теперь является рекомендацией W3C, которую мы иногда называем веб-стандартом . Чтобы спецификация дошла до этой стадии, должны были быть две реализации функции, которые мы можем видеть как в Firefox, так и в Chrome:

Поскольку это свойство прозрачно для пользователя, его можно абсолютно безопасно добавлять на любой сайт, даже если у вас много посетителей в браузерах, которые его не поддерживают. Если браузер не поддерживает сдерживание, посетитель получает то же, что и обычно, а те, кто поддерживает браузеры, получают повышенную производительность.
Я бы предположил, что это отличная вещь для добавления к любым компонентам, которые вы создаете в библиотеке компонентов или шаблонов, если вы работаете таким образом, вероятно, каждый компонент разработан как независимая вещь, которая не влияет на другие элементы в библиотеке. contain: content
, что делает его полезным дополнением.
Поэтому, если у вас есть страница, которая добавляет контент в DOM после загрузки, я бы порекомендовал попробовать — если вы получите какие-либо интересные результаты, сообщите мне об этом в комментариях!
Связанные ресурсы
Следующие ресурсы предоставят вам более подробную информацию о реализации сдерживания и потенциальных преимуществах производительности:
- «
contain
CSS contains», веб-документы MDN . - «Сдерживание CSS в Chrome 52», разработчики Google.
- «Модуль сдерживания CSS, уровень 1», рекомендация W3C.
- «Введение в сдерживание CSS», Мануэль Рего Касасновас.