内容范围 ( contain )
由于浏览器的进步,绝大部分页面都不会遭遇渲染元素的效能问题,但如果是较为复杂的页面,则可以透过 CSS 的 contain 样式属性近一步控制渲染的内容范围,这篇教学会介绍 contain 样式属性与 layout、style、paint、size、strict、content 等属性值的用法。
快速导览:
教学影片
搭配教学影片一起阅读,效果会更好!欢迎大家订阅 STEAM 教育学习网的 Youtube 频道。
认识 contain
使用 CSS contain 之前,需要先了解浏览器渲染网页的几个主要步骤:
- 解析 HTML:读取 HTML 并建立 DOM 结构树。
- 解析 CSS:解析 CSS 规则并建立 CSSOM ( CSS 对象模型 )。
- 合成 Render Tree:结合 DOM 与 CSSOM,过滤不可见元素。
- 布局 Layout:计算每个元素的大小、位置与盒子模型信息。
- 绘制 Painting:将边框、背景、文字等样式绘制到图层。
- 合成 Compositing:将多个图层合并,准备输出到屏幕。
- 重排 Reflow 重绘 Repaint:响应 DOM 或样式变化,重新计算布局或更新视觉内容。
前端开发者通常都是透过改善 HTML 和 CSS 结构、减少 JavaScript 对 HTML 和 CSS 的操作等做法,减轻浏览器在计算布局 Layout、绘制 Painting、合成 Compositing 的负担,进而加速网页渲染效率,而 contain 样式属性更能够明确定义计算范围,明确地告诉浏览器哪些元素是“独立的”,就像在网页上建立了隔离的区域,区域内的元素不会影响或被外部元素影响,
contain 样式属性主要影响的步骤:
- 影响布局 Layout:变更时只重新计算该元素内部的布局,不会影响外部。
- 影响绘制 Painting:重绘时只重绘该元素内部的像素,不会影响外部图层。
- 影响重排 Reflow、重绘 Repaint:让浏览器只针对局部、避免全页面重新计算与重绘。
虽然 contain 样式属性可以帮助开发者提升网页性能和布局稳定性。但需要注意下列事项:
- 浏览器的支援程度有所不同。
- 能提升复杂网页或大型应用程序的效能,但对于简单网页或小型应用程序没有太大影响。
- 需要搭配一些新的样式属性才能发挥真正功效,例如
size、inline-size、container等。
contain 撰写语法
contain 使用对应的关键字属性值,没有继承特性,下方列出相关属性值:
| 属性值 | 说明 |
|---|---|
| layout | 只进行元素本身布局,不考虑外部元素的变化。 |
| paint | 只绘制该元素及其子元素的“可见”部分,而不会考虑其周围元素的绘制,防止不必要的重绘。 |
| style | 只作用于计数器和引用的样式,使其不会影响到父元素或兄弟元素的样式影响。 |
| size | 只基于元素本身内容的 width 和 height 属性,而不考虑其子元素的内容大小。 |
| inline-size | 只基于元素本身内容的 width 属性,而不考虑其子元素的内容大小。 |
| content | 等于同时使用 layout、paint 和 style。 |
| strict | 等于同时使用 layout、paint、size 和 style 的缩写,表示最严格的内容范围。 |
contain 可以使用 1~3 组属性值,多组数形值之间使用空白分隔,下方列出相关写法:
div {
contain: layout; /* 使用一種內容範圍 */
contain: layout paint; /* 同時使用兩種內容範圍 */
contain: layout paint style; /* 同時使用三種內容範圍 */
contain: content; /* 等同 layout paint style */
contain: strict; /* 等同 layout paint style size */
}
contain 属性值 layout
当 contain 属性值为 layout 时,表示“元素会自成一个布局”,元素的内容不受其他元素或页面布局影响 ( 注意是元素内容,元素本身仍然属于页面中的容器 ),因此不论是 float、position 等排版相关功能都会在自己的容器区域中进行,下方范例会使用三个 div,红色 div 因为设定了 contain: layout,就算内容有出现浮动元素或定位,都会采用自身的容器作为布局依据,另外两个 div 就会参考页面本身或父元素进行定位。
<!-- HTML 程式碼 -->
<div class="a">
<h2>contain: layout;</h2>
<h3 class="fixed">fixed1</h3>
<h3 class="absolute">absolute1</h3>
<h3 class="float">float1</h3>
<h3>oxxo</h3>
</div>
<div class="b">
<h2>position: relative</h2>
<h3 class="fixed">fixed2</h3>
<h3 class="absolute">absolute2</h3>
<h3 class="float">float2</h3>
<h3>oxxo</h3>
</div>
<div class="c">
<h2>normal</h2>
<h3 class="fixed">fixed3</h3>
<h3 class="absolute">absolute3</h3>
<h3 class="float">float3</h3>
<h3>oxxo</h3>
</div>
<!-- CSS 程式碼 -->
<style>
div {
width: 250px;
height: 200px;
border: 1px solid #000;
margin: 10px;
float: left;
}
.a {contain: layout;} /* 設定 contain 為 layout */
.b {position: relative;} /* 設定 position 為 relative */
.a h3 {background: #f005;}
.b h3 {background: #0f05;}
.c h3 {background: #00f5;}
.fixed {
position: fixed;
bottom: 0;
right: 0;
}
.absolute {
position: absolute;
top: 0;
right: 0;
}
.float {float: left;}
h3 {
width: 100px;
height: 100px;
margin: 10px;
border: 1px solid #000;
}
</style>
contain 属性值 paint
当 contain 属性值为 paint 时,表示元素“只会渲染宽高尺寸里的内容”,范围外的内容都不会渲染,透过这个方法可以提高渲染性能,使用时虽然会呈现类似 overflow: hidden 的效果,但设定 contain: paint 元素内容的 position 定位会以自身布局为主,下方范例会用三组 div 呈现不同的效果,可以发现设定 contain: paint 的元素内容就算出现了 position: fixed 定位,仍然会以自身布局为参考依据。
<!-- HTML 程式碼 -->
<div class="a">
<h2>contain: paint;</h2>
<h3>apple</h3>
<h3>banana</h3>
<h3>oxxo</h3>
<h3 class="fixed">fixed1</h3>
</div>
<div class="b">
<h2>position: fixed</h2>
<h3>apple</h3>
<h3>banana</h3>
<h3>oxxo</h3>
<h3 class="fixed">fixed2</h3>
</div>
<div class="c">
<h2>normal</h2>
<h3>apple</h3>
<h3>banana</h3>
<h3>oxxo</h3>
<h3 class="fixed">fixed3</h3>
</div>
<!-- CSS 程式碼 -->
<style>
div {
width: 200px;
height: 200px;
border: 1px solid #000;
margin: 5px;
padding: 5px;
float: left;
}
.a {contain: paint;} /* 設定 contain 為 paint */
.a h3 {background: #f005;}
.b {overflow: hidden;}
.b h3 {background: #0f05;}
.c h3 {background: #00f5;}
h3 {
margin: 10px;
border: 1px solid #000;
width: 100px;
height: 40px;
}
.fixed {
position: fixed;
bottom: 0;
right: 0;
}
</style>
contain 属性值 style
当 contain 属性值为 style 时,表示元素的“计数器和引号会独立运作”,不会受到其他元素的计数器或引号设定影响,下方的范例会使用清单计数器相关样式属性,让清单中每一笔数据前方的显示数值,以间隔 50 的方式增加,但设定 contain: style 的清单并不会被影响。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li>
<li>banana</li>
<li class="a">oxxo</li>
<li class="a">oxxo</li>
<li class="a">oxxo</li>
<li>orange</li>
<li>papaya</li>
</ul>
<!-- CSS 程式碼 -->
<style>
ul {counter-reset: oxxo 100;}
li::before {
counter-increment: oxxo 50;
content: counter(oxxo)". ";
}
.a {contain: style;}
</style>
同理,如果内容使用 open-quote 和 close-quote 搭配虚拟元素的方式产生引号,只要是位于 contain:style 里的元素,就会断开引号的设定,不会延续引号的设定值影响别的元素 ( 这个做法不是适用 q 元素,因为 q 元素是使用 HTML 元素流产生引号内容,无法单纯受到 CSS 控制 ),下方范例有三组 div,因为第一组 div 设定了 contain: style,所以里面的引号序列不会影响到别人,而第二组 div 的引号序列就会影响到第三组。
<!-- HTML 程式碼 -->
<div class="a">
<h3><span>apple</span></h3>
<h3><span>contain: style</span></h3>
<h3><span>banana</span></h3>
<h3><span>oxxo</span></h3>
</div>
上方的引號不會影響下面
<div>
<h3><span>apple</span></h3>
<h3><span>contain: style</span></h3>
<h3><span>banana</span></h3>
<h3><span>oxxo</span></h3>
</div>
上方引號結尾會影響下面
<div>
<h3><span>apple</span></h3>
<h3><span>contain: style</span></h3>
<h3><span>banana</span></h3>
<h3><span>oxxo</span></h3>
</div>
<!-- CSS 程式碼 -->
<style>
div {
width: max-content;
border: 1px solid #000;
margin: 10px;
quotes: "❤️" "❤️" "🔥" "🔥" "💎" "💎" "🎵" "🎵";
}
h3 {
margin: 5px;
}
span::before {
content: open-quote;
}
.a {
contain: style;
}
</style>
contain 属性值 size 与 inline-size
当 contain 属性值为 size 时,表示元素“按照设定的宽高显示”,不会受到内容影响尺寸变化,如果没有设定宽高,就会根据容器类型设定宽高,当 contain 属性值为 inline-size 时,表示元素“按照设定的宽度显示”,宽度不会受到内容影响尺寸变化,但高度会随内容变化,如果没有设定宽度,宽度默认值为 0,下方范例会使用三个 div 表现这两个属性值的差异。
<!-- HTML 程式碼 -->
<div class="a">
<h2>contain: size;</h2>
<h3>apple</h3>
<h3>banana</h3>
<h3>oxxo</h3>
</div>
<div class="b">
<h2>contain: inline-size;</h2>
<h3>apple</h3>
<h3>banana</h3>
<h3>oxxo</h3>
</div>
<div class="c">
<h2>normal</h2>
<h3>apple</h3>
<h3>banana</h3>
<h3>oxxo</h3>
</div>
<!-- CSS 程式碼 -->
<style>
div {
border: 1px solid #000;
margin: 10px;
padding: 5px;
float: left;
}
.a, .b {margin-right: 250px;}
.a {contain: size;}
.a h3 {background: #f005;}
.b {contain: inline-size;}
.b h3 {background: #0f05;}
.c h3 {background: #00f5;}
h3 {
margin: 10px;
border: 1px solid #000;
width: 200px;
height: 40px;
}
</style>
contain 属性值 strict 与 content
当 contain 的 strict 和 content 是缩写格式的属性值,使用后等于同时设定多个属性值:
| 属性值 | 等同多个属性值同时使用 |
|---|---|
| content | 等于同时使用 layout、paint 和 style。 |
| strict | 等于同时使用 layout、paint、size 和 style 的缩写,表示最严格的内容范围。 |
下方范例会呈现这两种属性值的差异。
<!-- HTML 程式碼 -->
<div class="a">
<h2>contain: content;</h2>
<h3>apple</h3>
<h3>banana</h3>
<h3>oxxo</h3>
<h3>papaya</h3>
<h3 class="fixed">fixed1</h3>
</div>
<div class="b">
<h2>contain: strict;</h2>
<h3>apple</h3>
<h3>banana</h3>
<h3>oxxo</h3>
<h3>papaya</h3>
<h3 class="fixed">fixed2</h3>
</div>
<div class="c">
<h2>normal</h2>
<h3>apple</h3>
<h3>banana</h3>
<h3>oxxo</h3>
<h3>papaya</h3>
<h3 class="fixed">fixed3</h3>
</div>
<!-- CSS 程式碼 -->
<style>
div {
width: 250px;
min-height: 100px;
border: 1px solid #000;
margin: 10px;
padding: 5px;
float: left;
}
.a {contain: content;}
.a h3 {background: #f005;}
.b {contain: strict;}
.b h3 {background: #0f05;}
.c h3 {background: #00f5;}
h3 {
margin: 10px;
border: 1px solid #000;
width: 100px;
height: 40px;
}
.fixed {
position: absolute;
bottom: 0;
right: 0;
}
</style>
小结
CSS 的 contain 属性值通常是应用在需要大量动态刷新内容的页面,透过局部渲染的方式,可以提高网页的执行效能,但如果是一些静态页面或内容不多的页面,反而没有多大差别,有时反而透过原本的样式属性还比较容易理解和调整。
微信扫码关注
抖音扫码关注