”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 降低性能的两行 CSS(fps 到 ps)

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

发布于2024-11-03
浏览:454

我最近发布了《学习厕所》,如果您看过它,您可能会注意到背景中的动画,其中彩色圆圈在屏幕上对角移动。看起来像这样:

它在 Chrome 和 Safari 上运行良好,但我注意到 Firefox 上的性能严重下降。

性能太差了,我直接在 Firefox 中禁用了这个动画。

动画是如何运作的?

动画是使用两个嵌套的 div 构建的。外部 div 是网站 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 呈现到页面(尽管我已在此处概述),它会经历几个阶段。我们感兴趣的三个阶段是:

  • 布局 - 当浏览器计算页面上元素的大小和位置时
  • Paint - 绘制页面的所有视觉方面,如图像、颜色、阴影等
  • 复合 - 以正确的顺序将元素层叠在一起

管道的顺序如下所示:

布局 → 绘制 → 合成

布局和绘制过程可能会占用大量 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,而是使用平移属性移动整个背景元素。

从抽象的角度来看,动画是这样的:

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);
    }
}

浏览器不再对蒙版位置进行动画处理,这会在每个帧上触发布局。即使背景在每一帧上移动,通过翻译它也不会触发布局或绘制。您可以看到,唯一的绘制次数为每分钟 1,000 次。

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

眼尖的观众一定会发现一个问题。如果您还记得的话,背景的高度和宽度会填充视口。将背景向左和向上移动 24 像素,在视口中留下这个空白区域。

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

解决这个问题很简单,只需将蒙版尺寸添加到容器的宽度和高度即可:

.background-mask {
    --mask-size: 24px;

    width: calc(100%   var(--mask-size));
    height: calc(100%   var(--mask-size));
}

我们再在Firefox中看一下:

这可能不是一个完美的解决方案,但完成一个有趣的烟雾和镜子 CSS技巧总是让人有点满足。

版本声明 本文转载于:https://dev.to/andrico1234/the-two-lines-of-css-that-tanked-performance-120fps-to-40fps-3lnj?1如有侵犯,请联系[email protected]删除
最新教程 更多>

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3