我正在尝试实际了解Chrome的布局→绘制→合成管道是如何工作的。 在我的测试中,我对以下情况下Chrome的行为感到困惑。(Codepen)
var button = document.querySelector('button');
var red = document.querySelector('.red');
var blue = document.querySelector('.blue');
button.addEventListener('click', function() {
red.classList.toggle('test');
})
.wrapper {
height: 100%;
width: 100%;
background-color: teal;
position: static;
}
.square {
height: 200px;
width: 200px;
position: static;
transition: transform 0.3s ease,
opacity 0.3s ease,
width 0.3s ease,
height 0.3s ease,
box-shadow 0.3s ease;
}
.red {
/* position: absolute; */
background-color: red;
top: 100px;
left: 100px;
/* will-change: transform; */
opacity: 1;
}
.blue {
background-color: blue;
z-index: 3;
}
.test {
/* transform: translate3d(50px, 50px, 0); */
/* opacity: 0; */
width: 60px;
height: 60px;
/* box-shadow: 0px 0px 0px 10px rgba(0,0,0,.5) */
}
button {
position: fixed;
right: 100px;
top: 50px;
z-index: 10000;
font-weight: bold;
background-color: yellow;
padding: 5px 10px;
/* will-change: transform; */
}
<div class="wrapper">
<div class="red square"></div>
<div class="blue square"></div>
</div>
<button>Click</button>
重现步骤
- 使用Chrome浏览器;
- 在开发者工具中开启高亮重绘;
- 打开图层面板;
- 点击黄色按钮,切换红色正方形的大小;
- 查看被标记为“已重绘”的内容以及当前的图层;
- 尝试在改变红色正方形
position
之后执行上述操作。
我们有一个包含红色正方形和蓝色正方形的容器元素。在Chrome的图层面板中,整个容器显示为一个图层。
如果两个正方形都是
static
定位,当我转换红色正方形的宽度和高度时,我可以看到整个图层被重新绘制,这很合理,因为如果所有三个元素都在同一图层中,更改一个元素的尺寸将导致整个图层的最终结果改变,所以整个图层必须被重新绘制。如果我将红色正方形设置为
absolute
定位(您可以取消注释.red
样式规则中的行),当我转换其宽度和高度时,尽管开发者工具仍然显示为一个图层,但只有在该图层内的红色正方形被标记为已重绘。
问题
第二种情况对我来说没有意义。
如果两个正方形和包装元素都在同一图层中,更改一个元素不应影响整个图层并导致整个图层重新绘制,而不是只有红色正方形?
补充问题
Chrome浏览器在布局阶段(或确定图层的任何阶段)是否会将某些元素分成单独的图层(例如由于position
属性)?这就是它能够分别重新绘制它们的原因吗?在合成阶段之后,它是否会将它们合并,以便开发人员只看到一个图层?
相关背景
我大致了解现代浏览器的绘制过程如下:
- 在布局阶段,浏览器将CSS与HTML信息结合起来,以确定屏幕上可视元素的位置和尺寸。我还认为这是它确定有多少个渲染图层的时间(例如由于
will-change
)。 - 在绘制阶段,浏览器为每个图层制作一个帧缓冲区,其中包含基于布局数据的每个像素应显示的颜色信息。
- 在合成阶段,GPU根据绘制阶段生成的数据将所有图层组合在一起,并将最终结果发送到屏幕上。
position: absolute
情况?(如果是这样,简单地在网上搜索就足够了:https://www.w3.org/TR/CSS2/visuren.html#absolute-positioning) - Kaiidoposition: absolute
只是一个例子。我的问题实质是为什么我只看到整个层中的一个元素被重新绘制,而不是整个层。也许我表达得不对,我不知道。 - Dimitris Karagiannis