首页 >web前端 >css教程 >降低性能的两行 CSS(fps 到 ps)

降低性能的两行 CSS(fps 到 ps)

WBOY
WBOY原创
2024-09-03 11:09:21944浏览

我最近发布了 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 元素负责创建跨越其父容器的整个宽度和高度的渐变。像这样:

The Two Lines of CSS That Tanked Performance (fps to ps)

外部 .background-mask 负责两件事:

  1. 它将位置设置为固定,并使容器填充视口的整个尺寸。
  2. 在渐变上创建点状蒙版

这确保了点的颜色是其正下方渐变的颜色:

The Two Lines of CSS That Tanked Performance (fps to ps)

这是我上面描述的所有内容的 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 次油漆。

The Two Lines of CSS That Tanked Performance (fps to ps)

即使绘制数量如此之多,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.

The Two Lines of CSS That Tanked Performance (fps to ps)

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.

The Two Lines of CSS That Tanked Performance (fps to ps)

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中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn