contain

Baseline 已广泛支持

此特性已经十分成熟,可在许多设备和浏览器版本上使用。自 2022 年 3 月起,它已在各浏览器中可用。

contain CSS 属性表示一个元素及其内容尽可能独立于文档树的其余部分。包含功能可以将 DOM 的一个子部分隔离出来,通过将布局、样式、绘制、尺寸或它们的任意组合的计算限制在一个 DOM 子树内而不是整个页面,从而提供性能优势。包含功能还可以用于限定 CSS 计数器和引用。

试一试

contain: none;
contain: size;
contain: layout;
contain: paint;
contain: strict;
<section class="default-example" id="default-example">
  <div class="card" id="example-element">
    <h2>Element with '<code>contain</code>'</h2>
    <p>
      The Goldfish is a species of domestic fish best known for its bright
      colors and patterns.
    </p>
    <div class="fixed"><p>Fixed right 4px</p></div>
  </div>
</section>
h2 {
  margin-top: 0;
}

#default-example {
  text-align: left;
  padding: 4px;
  font-size: 16px;
}

.card {
  text-align: left;
  border: 3px dotted;
  padding: 20px;
  margin: 10px;
  width: 85%;
  min-height: 150px;
}

.fixed {
  position: fixed;
  border: 3px dotted;
  right: 4px;
  padding: 4px;
  margin: 4px;
}

CSS 包含有四种类型:尺寸、布局、样式和绘制,它们设置在容器上。该属性是五个标准值子集或两个简写值之一的空格分隔列表。容器内包含属性的更改不会传播到包含元素之外,影响页面的其余部分。包含的主要好处是浏览器不必经常重新渲染 DOM 或页面布局,从而在渲染静态页面时带来微小的性能提升,在更动态的应用程序中带来更大的性能提升。

在页面上,如果元素组应该相互独立,使用 contain 属性会很有用,因为它可以防止元素内部产生超出其边框的副作用。

注意: 对此属性使用 layoutpaintstrictcontent 值会创建

  1. 一个新的包含块(对于 position 属性为 absolutefixed 的后代元素)。
  2. 一个新的堆叠上下文
  3. 一个新的块格式化上下文

语法

css
/* Keyword values */
contain: none;
contain: strict;
contain: content;
contain: size;
contain: inline-size;
contain: layout;
contain: style;
contain: paint;

/* Multiple keywords */
contain: size paint;
contain: size layout paint;
contain: inline-size layout;

/* Global values */
contain: inherit;
contain: initial;
contain: revert;
contain: revert-layer;
contain: unset;

contain 属性可以具有以下任意值

  • 关键字 none
  • 一个或多个空格分隔的关键字 size(或 inline-size)、layoutstylepaint,任意顺序
  • 简写值 strictcontent 之一

关键字具有以下含义

none

元素正常渲染,不应用任何包含。

strict

所有包含规则都应用于元素。这等同于 contain: size layout paint style

content

除了 size 之外的所有包含规则都应用于元素。这等同于 contain: layout paint style

size

尺寸包含应用于元素的行内和块方向。元素的尺寸可以独立计算,忽略子元素。此值不能与 inline-size 组合使用。

inline-size

行内尺寸包含应用于元素。元素的行内尺寸可以独立计算,忽略子元素。此值不能与 size 组合使用。

layout

元素的内部布局与页面的其余部分隔离。这意味着元素外部的任何内容都不会影响其内部布局,反之亦然。

style

对于可以影响不仅仅是元素及其后代的属性,其效果不会超出包含元素。计数器和引用被限定在元素及其内容之内。

paint

元素的后代不会显示在其边界之外。如果包含框在屏幕外,浏览器无需绘制其包含的元素——这些元素也必须在屏幕外,因为它们完全被该框包含。如果后代溢出包含元素的边界,那么该后代将被剪裁到包含元素的边框。

正式定义

初始值none
应用于所有元素
继承性
计算值同指定值
动画类型不可动画化

正式语法

contain = 
none |
strict |
content |
[ [ size | inline-size ] || layout || style || paint ] |
view-transition

示例

绘制包含

以下示例展示了如何使用 contain: paint 来防止元素的后代在其边界之外绘制。

css
div {
  width: 100px;
  height: 100px;
  background: red;
  margin: 10px;
  font-size: 20px;
}

.contain-paint {
  contain: paint;
}
html
<div class="contain-paint">
  <p>This text will be clipped to the bounds of the box.</p>
</div>
<div>
  <p>This text will not be clipped to the bounds of the box.</p>
</div>

布局包含

请看下面的示例,它展示了应用和未应用布局包含时元素的行为

html
<div class="card contain-layout">
  <h2>Card 1</h2>
  <div class="fixed"><p>Fixed box 1</p></div>
  <div class="float"><p>Float box 1</p></div>
</div>
<div class="card">
  <h2>Card 2</h2>
  <div class="fixed"><p>Fixed box 2</p></div>
  <div class="float"><p>Float box 2</p></div>
</div>
<div class="card">
  <h2>Card 3</h2>
  <!-- ... -->
</div>
css
.card {
  width: 70%;
  height: 90px;
}

.fixed {
  position: fixed;
  right: 10px;
  top: 10px;
  background: coral;
}

.float {
  float: left;
  margin: 10px;
  background: aquamarine;
}

.contain-layout {
  contain: layout;
}

第一张卡片应用了布局包含,其布局与页面的其余部分隔离。我们可以在页面上的其他位置重用这张卡片,而无需担心其他元素的布局重新计算。如果浮动元素与卡片边界重叠,页面其余部分的元素不受影响。当浏览器重新计算包含元素的子树时,只重新计算该元素。包含元素外部的任何内容都不需要重新计算。此外,固定框使用卡片作为布局容器来定位自身。

第二张和第三张卡片没有包含。第二张卡片中固定框的布局上下文是根元素,因此固定框位于页面的右上角。一个浮动元素与第二张卡片的边界重叠,导致第三张卡片出现意外的布局偏移,这在 <h2> 元素的定位中可见。当重新计算发生时,它不限于一个容器。这会影响性能并干扰页面的其余布局。

样式包含

样式包含将计数器引用限定在包含元素内。对于 CSS 计数器,counter-incrementcounter-set 属性被限定在该元素上,就像该元素位于文档的根部一样。

包含和计数器

下面的示例展示了应用样式包含时计数器的工作方式

html
<ul>
  <li>Item A</li>
  <li>Item B</li>
  <li class="container">Item C</li>
  <li>Item D</li>
  <li>Item E</li>
</ul>
css
body {
  counter-reset: list-items;
}

li::before {
  counter-increment: list-items;
  content: counter(list-items) ": ";
}

.container {
  contain: style;
}

如果没有包含,计数器将为每个列表项从 1 递增到 5。样式包含导致 counter-increment 属性被限定在元素的子树中,计数器重新从 1 开始

包含和引用

CSS 引用也同样受到影响,即与引用相关的 content 值被限定在元素内

html
<!-- With style containment -->
<span class="open-quote">
  outer
  <span class="contain-style">
    <span class="open-quote">inner</span>
  </span>
</span>
<span class="close-quote">close</span>
<br />
<!-- Without containment -->
<span class="open-quote">
  outer
  <span>
    <span class="open-quote">inner</span>
  </span>
</span>
<span class="close-quote">close</span>
css
body {
  quotes: "[" "]" "‹" "›";
}
.open-quote::before {
  content: open-quote;
}

.close-quote::after {
  content: close-quote;
}

.contain-style {
  contain: style;
}

由于包含,第一个结束引用忽略了内部 span,而是使用了外部 span 的结束引用

规范

规范
CSS 包含模块第 2 级
# contain-property

浏览器兼容性

另见