」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 降低效能的兩行 CSS(fps 到 ps)

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

發佈於2024-11-03
瀏覽:244

我最近發布了《學習廁所》,如果您看過它,您可能會注意到背景中的動畫,其中彩色圓圈在螢幕上對角移動。看起來像這樣:

它在 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]刪除
最新教學 更多>
  • 如何將單一輸入欄位設定為分區輸入?
    如何將單一輸入欄位設定為分區輸入?
    將輸入欄位設為分區輸入有多種方法可用於建立一系列分區輸入欄位。一種方法利用「字母間距」來分隔單一輸入欄位內的字元。此外,「background-image」和「border-bottom」樣式可以進一步增強多個輸入欄位的錯覺。 CSS Snippet以下 CSS 程式碼示範如何建立所需的效果:#pa...
    程式設計 發佈於2024-11-05
  • 用 Go 建構一個簡單的負載平衡器
    用 Go 建構一個簡單的負載平衡器
    负载均衡器在现代软件开发中至关重要。如果您曾经想知道如何在多个服务器之间分配请求,或者为什么某些网站即使在流量大的情况下也感觉更快,答案通常在于高效的负载平衡。 在这篇文章中,我们将使用 Go 中的循环算法构建一个简单的应用程序负载均衡器。这篇文章的目的是逐步了解负载均衡器的工作原理。 ...
    程式設計 發佈於2024-11-05
  • 如何以超連結方式開啟本機目錄?
    如何以超連結方式開啟本機目錄?
    透過超連結導航本地目錄嘗試在連結互動時啟動本地目錄視圖時,您可能會遇到限制。然而,有一個解決方案可以解決這個問題,並且可以在各種瀏覽器之間無縫運作。 實作方法因為從HTML 頁面直接開啟路徑或啟動瀏覽器是由於安全原因受到限制,更可行的方法是提供可下載的連結( .URL 或.LNK)。 建議路徑:.U...
    程式設計 發佈於2024-11-05
  • 為什麼 Makefile 會拋出 Go 指令的權限被拒絕錯誤?
    為什麼 Makefile 會拋出 Go 指令的權限被拒絕錯誤?
    在執行Go 時Makefile 中出現權限被拒絕錯誤透過Makefile 執行Go 指令時可能會遇到「權限被拒絕」錯誤,即使你可以直接執行它們。這種差異是由於 GNU make 中的問題引起的。 原因:當您的 PATH 上有一個目錄包含名為“go.gnu”的子目錄時,就會出現此錯誤。 ”例如,如果您...
    程式設計 發佈於2024-11-05
  • parseInt 函數中 Radix 參數的意義是什麼?
    parseInt 函數中 Radix 參數的意義是什麼?
    parseInt 函數中 Radix 的作用parseInt 函數將字串轉換為整數。然而,它並不總是採用以 10 為基數的數字系統。若要指定所需的基數,請使用基數參數。 理解基數基數是指單一數字表示的值的數量。例如,十六進制的基數為 16,八進制的基數為 8,二進制的基數為 2。 為什麼要用基數? ...
    程式設計 發佈於2024-11-05
  • 如何使用 JavaScript 將連結保留在同一選項卡中?
    如何使用 JavaScript 將連結保留在同一選項卡中?
    在同一分頁和視窗中導覽連結您可能會遇到想要在同一視窗和分頁中開啟連結的情況作為當前頁面。但是,使用 window.open 函數通常會導致在新分頁中開啟連結。為了解決這個問題,您可以使用name 屬性,如下所示:window.open("https://www.youraddress.co...
    程式設計 發佈於2024-11-05
  • 如何解決Python中的循環依賴?
    如何解決Python中的循環依賴?
    Python 中的循環依賴使用 Python 模組時遇到循環依賴可能是一個令人沮喪的問題。在這個特定場景中,我們有兩個文件,node.py 和 path.py,分別包含 Node 和 Path 類別。 最初,path.py 使用 from node.py import * 導入 node.py。但是...
    程式設計 發佈於2024-11-05
  • MariaDB 與 MySQL:開發人員需要了解什麼
    MariaDB 與 MySQL:開發人員需要了解什麼
    MariaDB 和 MySQL 是著名的開源 RDBMS,但儘管它們有著共同的歷史,但它們在功能和效能方面卻有所不同。本文快速強調了主要差異,幫助開發人員決定哪個資料庫最適合他們的需求。 差異和範例 儲存引擎,MariaDB 對 Aria 和 MyRocks 等引擎的擴充支援提供了...
    程式設計 發佈於2024-11-05
  • 為什麼我的 Goroutine 遞增變數會產生意外的結果?
    為什麼我的 Goroutine 遞增變數會產生意外的結果?
    這是編譯器最佳化的結果嗎? 在此程式碼片段中,啟動了一個 goroutine 並重複遞增變數 i:package main import "time" func main() { i := 1 go func() { for { ...
    程式設計 發佈於2024-11-05
  • 利用 AI 快速學習 Node.js - 第 4 天
    利用 AI 快速學習 Node.js - 第 4 天
    今天,借助ChatGPT繼續學習Node.js,重點是非同步程式設計。這是 Node.js 中最重要的概念之一,我很高興能夠開始掌握它。 理論 在 Node.js 中,非同步程式設計因其非阻塞、事件驅動的架構而至關重要。這意味著文件讀取、資料庫查詢或網路請求等操作在等待結果時不會阻塞其他程式碼的執...
    程式設計 發佈於2024-11-05
  • Java 可以定義帶有嵌入引號的字串而不轉義嗎?
    Java 可以定義帶有嵌入引號的字串而不轉義嗎?
    揭開Java 使用嵌入式引號定義字串的替代方法在Java 中處理字串時,您常常會在文字中遇到大量引號,導致繁瑣的轉義和可讀性挑戰。雖然其他語言提供了處理這種情況的語法,但 Java 缺乏類似的選項。 問題: Java 是否提供了另一種方法來定義帶有嵌入引號的字串而不訴諸轉義? 答案: 雖然Java ...
    程式設計 發佈於2024-11-05
  • 耐用的 Python:建立防彈的長期運作工作流程,變得簡單
    耐用的 Python:建立防彈的長期運作工作流程,變得簡單
    在现代软件开发中,创建强大的工作流程来连接来自各种服务的 API 并处理同步和异步事件是一个常见的挑战。传统方法涉及使用队列、微服务和状态管理系统的组合来构建可扩展的应用程序。虽然有效,但这种架构带来了巨大的开销:设置和维护消息队列等基础设施、运行服务器或 lambda 函数、管理数据库中的状态以及...
    程式設計 發佈於2024-11-05
  • 使用 Node.js 建立即時儀表板
    使用 Node.js 建立即時儀表板
    介紹 在當今快節奏的商業世界中,組織存取即時數據以做出明智的決策至關重要。這就是使用 Node.js 建立即時儀表板發揮作用的地方。 Node.js 是一種流行的、輕量級的、高效的 JavaScript 執行環境,近年來獲得了極大的普及。在本文中,我們將討論專門使用 Node.js...
    程式設計 發佈於2024-11-05
  • 以下是一些適合您的文章的基於問題的標題,重點關注問題和解決方案:

* 如何跨子域共享localStorage資料?
* 想要在您之間共享本機儲存數據
    以下是一些適合您的文章的基於問題的標題,重點關注問題和解決方案: * 如何跨子域共享localStorage資料? * 想要在您之間共享本機儲存數據
    如何跨子網域共享 localStorage許多網站使用 localStorage 而不是 cookie 來儲存數據,因為它提供了更好的效能和安全性。然而,localStorage 在處理子網域時可能會帶來挑戰,因為每個子網域都有自己單獨的 localStorage 物件。當使用者同時使用主網域(例如...
    程式設計 發佈於2024-11-05
  • C++ 是否像 Python 一樣有遞迴深度限制?
    C++ 是否像 Python 一樣有遞迴深度限制?
    C 是否像 Python 一樣有遞迴深度限制? 與 Python 不同,Python 由於其解釋性而具有最大遞歸深度,C 是編譯的,並且沒有直接面對這樣的限制。然而,C 確實有作業系統透過其分配的堆疊大小施加的遞歸限制。 C 中的堆疊大小通常明顯小於可用 RAM,並且可以在作業系統內進行修改(例如使...
    程式設計 發佈於2024-11-05

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3