我最近发布了 Learn WC,如果您看过它,您可能会注意到背景中的动画,其中彩色圆圈在屏幕上对角移动。看起来像这样:
它在 Chrome 和 Safari 上运行良好,但我注意到 Firefox 上的性能严重下降。
性能太差了,我直接在 Firefox 中禁用了这个动画。
动画是使用两个嵌套的 div 构建的。外部 div 是网站 body 标签的第一个子级。
<body> <div class="background-mask"> <div class="background-gradient"></div> </div> <!-- Rest of content --> </body>
.background-gradient 元素负责创建跨越其父容器的整个宽度和高度的渐变。像这样:
外部 .background-mask 负责两件事:
这确保了点的颜色是其正下方渐变的颜色:
这是我上面描述的所有内容的 CSS:
.background-mask { --mask-size: 24px; /* Position Styles */ position: fixed; width: 100%; height: 100%; z-index: -1; /* Mask Styles */ mask-image: radial-gradient(black 2px, transparent 2px); mask-size: var(--mask-size) var(--mask-size); mask-position: 0px 0px; animation: mask-move 3s infinite linear; } .background-gradient { background: var(--red); background-image: var(--gradient); width: 100%; height: 100%; } @keyframes mask-move { 0% { mask-position: 0px 0px; } 100% { mask-position: var(--mask-size) var(--mask-size); } } @media (prefers-reduced-motion: reduce) { .hero-background-mask { animation: none; } }
如果您有兴趣了解有关 CSS 中蒙版的更多信息,那么我可以推荐 Ahmad Shadeed 撰写的这篇综合文章
并非所有 CSS 属性的动画效果都是一样的。无需过多讨论浏览器如何将 HTML 呈现到页面(尽管我已在此处概述),它会经历几个阶段。我们感兴趣的三个阶段是:
管道的顺序如下所示:
布局→绘制→合成
布局和绘制过程可能会占用大量 CPU 资源,因此尝试减少 CSS 触发管道中各阶段的次数非常重要*。* 浏览器通过优化某些属性的性能在某种程度上提供了帮助,例如跳过渲染管道的整个阶段,其他人可以利用硬件加速将计算从CPU转移到GPU。
对某些属性进行动画处理,例如平移和不透明度,都可以避免触发布局并使用硬件加速。
遗憾的是,动画蒙版位置时并非如此。我查看了 Chrome,发现背景 div 的绘制计数在每一帧上都在增加。几秒钟后,它已经触发了超过 1,000 次油漆。
即使绘制数量如此之多,Chrome 上的动画也感觉很流畅。然而,在 Firefox 上感觉超级卡顿。令人烦恼的是,我找不到测量 Firefox 上的绘制计数的方法,因此我对 Firefox 糟糕性能所做的任何假设都纯粹是猜测。
我确实注意到动画对于小型设备来说很好,但随着屏幕尺寸的增加而变得更糟。我的工作原理是,Firefox 不会对每个 24x24 蒙版进行批处理布局触发器,这会导致当存在更多 24x24 蒙版时 FPS 下降。再说一次,我在这里可能完全错了。
我需要依靠性能更高的属性,例如translate,而不是对优化不佳的 CSS 属性(如 mask-position )进行动画处理。
解决方案不是将蒙版移动 24px,而是使用平移属性移动整个背景元素。
From an abstract standpoint, this is how the animation looks:
Here’s the two line change in the CSS:
/* --mask-size = 24px */ @keyframes mask-move { 0% { transform: translate(calc(var(--mask-size) * -1), calc(var(--mask-size) * -1)); } 100% { transform: translate(0px, 0px); } }
The browser no longer animates the mask-position, which triggered a layout on each frame. Even though the background moves on each frame, through translate it doesn’t trigger a layout or a paint. You can see that the only paints twice, down from 1,000+ every minute.
Eagle-eyed viewers will have spotted a problem. If you remember, the height and width of the background fills the viewport. Shifting the background left and up by 24px leaves us with this empty space in the viewport.
Solving it is as simple as adding the mask size to the width and height of the container:
.background-mask { --mask-size: 24px; width: calc(100% + var(--mask-size)); height: calc(100% + var(--mask-size)); }
Let’s take a look again in Firefox:
It may not be a perfect solution, but it’s always a little satisfying pulling off a fun smoke and mirrors CSS trick.
以上是降低性能的两行 CSS(fps 到 ps)的详细内容。更多信息请关注PHP中文网其他相关文章!