为什么转换框阴影会导致整个页面重新绘制



当我将鼠标悬停在具有动画box-shadow的元素上时,我注意到我的页面滞后。使用Chrome的Devtools,我注意到当我悬停在元素上时,整个页面都被重新绘制了。重新绘制需要40多毫秒,即大约3帧。transition持续约半秒,因此在半秒期间存在明显的滞后。

如何将重新绘制限制为仅包含长方体阴影的区域?

下面是一个演示:http://jsfiddle.net/8sa41xfL/

html,body{
    height:100%;
}
#test{
    background:red;
    height:100px;
    width:200px;
    transition:box-shadow 0.5s;
}
#test:hover{
    box-shadow:0 0 3px 3px rgba(0,0,0,0.3);
}
<div id=test></div>

transform:translateZ(0)在我的页面上不起作用,但它起作用。除了transform:translateZ(0)之外,还有其他修复程序吗?

正如皮埃尔答案中链接的线程中所提到的,box-shadow的绘制成本很高。解释为什么它很昂贵需要深入了解渲染的工作方式,而我没有足够的知识来完全解释它。但这个答案试图解释为什么整个页面都被重新绘制,以及避免它的各种可能方法


根据CSS触发器网站:

更改长方体阴影不会触发任何几何体更改,这很好。但由于它是一种视觉特性,它将导致绘画的发生。喷漆通常是一项超昂贵的操作,因此您应该谨慎。

一旦绘制了任何像素,页面将被合成在一起。


为什么每次都要重新绘制整个页面

以下文章解释了绘画在高水平上的实际工作方式:

  • HTML5岩石-浏览器如何工作-绘画
  • Chromium项目-GPU在Chrome中的加速渲染

基于这些文章,我们可以看到DOM树中产生视觉输出的每个节点都被视为RenderObject,每个RenderObject都是RenderLayer的一部分。每当发生更改时,渲染器(或渲染对象(都会使其在屏幕上的矩形(或RenderLayer(无效,并触发重新绘制。

在这种情况下,整个页面似乎都被重新绘制了,因为#test元素不保证创建单独的RenderLayer(基于Chromium Project文章中提到的标准(,因此成为根渲染层的一部分。因为它是根渲染层的一部分,所以每次需要重新绘制时,整个页面都会被重新绘制。

下面的片段证明了上述断言是正确的。在这里,我添加了一个#cover元素(带定位(来封装#test元素。现在,由于#cover元素具有明确的定位,它在根层之上创建了一个额外的层,#test成为这个中间层的一部分。现在,我们可以看到box-shadow转换只重新绘制这个中间层,而不是整个页面。

html,
body {
  height: 100%;
}
#cover {
  position: relative;
}
#test {
  background: red;
  height: 100px;
  width: 200px;
  transition: box-shadow 0.5s;
}
#test:hover {
  box-shadow: 0 0 3px 3px rgba(0, 0, 0, 0.3);
}
<div id=cover>
  <div id=test></div>
</div>


解决方案是什么

有各种CSS属性可以用来解决这个问题,但它们似乎都指向同一个高级别的点,即为#test元素创建一个单独的渲染层。

以下是为#test元素创建单独渲染层的几个可能选项:

  • 通过添加明确的位置属性-这与Pierre的回答中描述的选项相同,但absolute定位并不是唯一的选项。即使是relative定位也能解决这个问题

    html,
    body {
      height: 100%;
    }
    #test {
      position: relative;
      background: red;
      height: 100px;
      width: 200px;
      transition: box-shadow 0.5s;
    }
    #test:hover {
      box-shadow: 0 0 3px 3px rgba(0, 0, 0, 0.3);
    }
    <div id=test></div>

  • 通过添加透明度(不透明度(-浏览器似乎甚至将opacity: 0.99视为添加透明度,这非常有用,因为添加透明度不会造成任何视觉差异。

    html,
    body {
      height: 100%;
    }
    #test {
      background: red;
      height: 100px;
      width: 200px;
      opacity: 0.99;
      transition: box-shadow 0.5s;
    }
    #test:hover {
      box-shadow: 0 0 3px 3px rgba(0, 0, 0, 0.3);
    }
    <div id=test></div>

  • 通过添加一个伪CSS过滤器-我们可以添加一个filter: blur(0px),因为它什么都不做。

    html,
    body {
      height: 100%;
    }
    #test {
      background: red;
      height: 100px;
      width: 200px;
      -webkit-filter: blur(0px);
      filter: blur(0px);
      transition: box-shadow 0.5s;
    }
    #test:hover {
      box-shadow: 0 0 3px 3px rgba(0, 0, 0, 0.3);
    }
    <div id=test></div>

CSS框阴影的绘制成本很高。点击此处阅读更多关于SO的信息。

如果希望避免重新绘制整页,请在元素上使用position:absolute。这将在不影响整个页面的情况下重新绘制元素周围的区域。不停摆弄

相关内容

  • 没有找到相关文章

最新更新