我最近發布了 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中文網其他相關文章!