首頁  >  文章  >  web前端  >  降低效能的兩行 CSS(fps 到 ps)

降低效能的兩行 CSS(fps 到 ps)

WBOY
WBOY原創
2024-09-03 11:09:21927瀏覽

我最近發布了 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