CSS свойство contain позволяет объяснить браузеру структуру вашего макет для оптимизации производительности. Однако оно имеет кое-какие побочные эффекты для самого макета.

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

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

Проблема перерисовки макета

Если вы создаете простые веб-страницы, которые не добавляют или не изменяют элементы динамически после загрузки с помощью JavaScript, вам не нужно беспокоиться о проблеме, которую решает CSS Containment. Браузеру нужно отрисовать ваш макет только один раз при загрузке страницы.

Удерживание становится полезным, когда вы хотите добавить элементы на свою страницу без необходимости перезагружать ее пользователю. В примере ниже создан список событий. Если нажать кнопку, первое событие будет изменено, добавлен плавающий элемент (со свойством float) и изменен текст:

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

Как помогает удерживание

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

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

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

Использование удержания

Свойство contain может иметь различные значения, основные из них: layout, paint и size.

LAYOUT

Значение layout дает самые большие преимущества. Чтобы его использовать, используйте следующую запись:

.element {
  contain: layout;
}

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

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

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

Блок также создает контекст наложения. Следовательно, z-index будет работать с этим элементом, а его дочерние элементы будут позиционироваться на основе этого нового контекста.

Взглянем на тот же пример, на этот раз с contain: layout, и заметим, что когда добавляется плавающий элемент, он больше не вылезает из нижней части блока. Это означает, что наш новый контекст форматирования блока в действии.

PAINT

Для использования значения paint, используйте:

.element {
  contain: paint;
}

При данном значении contain происходит то же поведение в макете, что и с layout: блок становится независимым контекстом форматирования, удерживающим блоком для позиционированных элементов и устанавливает контекст наложения.

Что особенного делает paint - это указывает браузеру, что элементы внутри удерживающего блока не будут видны за пределами этого блока. По сути, содержимое будет привязано к блоку.

Можем увидеть это на простом примере. Если мы зададим нашему элементу высоту, плавающий элемент все равно будет выступать за пределы блока:

А вот как это будет выглядеть с contain: paint - плавающий элемент обрежется по размеру блока:

SIZE

Этот тип удерживания скорее всего, вызовет у вас проблемы, если вы не совсем понимаете, как он работает. Чтобы применить его, используйте:

.element {
  contain: size;
}

Если вы используете contain: size, вы сообщаете браузеру, что знаете размер элемента, и он не изменится. Это означает, что если у вас есть блок, размер которого автоматически изменяется в зависимости от контента, он будет обрабатываться так, как если бы содержимое не имело размера, другими словами он просто схлопнется.

В примере ниже у элементов li не указана высота и им добавлено свойство contain: size. Как видим, все элементы схлопнуты, будто внутри вообще нет содержимого

Если вы зададите элементам высоту, то при использовании contain: size она будет учитываться. Само по себе ограничение размера не будет создавать новый контекст форматирования и, следовательно, не будет содержать плавающих элементов и отступов, как это будет сделано с использованием layout и paint.

Поддержка браузерами
chrome
Chrome
52
firefox
Firefox
69
internet explorer
IE
 
edge
Edge
79
safari
Safari
 
opera
Opera
40