我想知道以下HTML文档中过度重绘的原因和解决方法。在Chrome上,重绘可以在devtool -> rendering panel -> Paint flashing
中可视化。问题本身有很多解决方法,但我更感兴趣的是为什么会发生这种重绘。
for (const el of document.querySelectorAll(".contents > img")) {
el.addEventListener("mouseenter", function() { this.classList.add("easy-in-out", "scale-150", "scale", "z-20"); });
el.addEventListener("mouseleave", function() { this.classList.remove("easy-in-out", "scale-150", "scale", "z-20"); });
}
个字符
(然而,Chrome似乎无法在iframe内显示“Paint flashing”,因此我也在下面提供了最小的单文件片段,或在线https://jjyyxx.github.io/grid-repaint/)
<!DOCTYPE html>
<html>
<body style="width: 410px;">
<div class="grid grid-cols-2">
<div class="contents"><img class="relative transition p-1" src="https://picsum.photos/200"></div>
<div class="contents"><img class="relative transition p-1" src="https://picsum.photos/200"></div>
<div class="contents"><img class="relative transition p-1" src="https://picsum.photos/200"></div>
<div class="contents"><img class="relative transition p-1" src="https://picsum.photos/200"></div>
</div>
<script src="https://cdn.tailwindcss.com"></script>
<script>
for (const el of document.querySelectorAll(".contents > img")) {
el.addEventListener("mouseenter", function() { this.classList.add("easy-in-out", "scale-150", "scale", "z-20"); });
el.addEventListener("mouseleave", function() { this.classList.remove("easy-in-out", "scale-150", "scale", "z-20"); });
}
</script>
</body>
</html>
型
当您mouseleave
一个图像元素时,淡入淡出过渡将导致其所有后续图像元素重新绘制。对于许多图像或一些大型图像,此行为会导致帧丢失。
由于布局没有改变,在我看来,只有悬停的元素应该被重新绘制。如果style="will-change: scale;"
使用选择器.contents > img
添加到div
s,可以实现这种期望的行为。但是文档表明广泛使用will-change
不是最佳实践。
**可在Chrome v120.0.6099.72上重现。**删除图像元素上的relative
似乎可以修复此重绘。
2条答案
按热度按时间sr4lhrrt1#
您可以将
transform-gpu
添加到所有<img>
标记中:字符串
这将把它们放在单独的层中,并使用GPU进行转换。
hfsqlsce2#
问题是Chrome将页面的部分分组到更大的图层中,这通常有助于提高性能,因为它需要跟踪的页面部分较少。缺点是,如果您对其中一个图层的一部分进行动画处理,则整个图层都会重新绘制。
不同的解决方法都迫使Chrome将你应用它们的元素分离到它们自己的更小的层中。当你这样做时,显然有一个性能权衡。一个解决方法是只在过渡运行时将这些CSS修复应用到元素,然后在完成时将其删除。
你可能会发现这篇文章很有趣,它深入到了导致janky渲染的每一个细节。
https://www.sderosiaux.com/articles/2015/03/01/perfmatters/