首頁  >  文章  >  web前端  >  深入了解css中的will-change屬性

深入了解css中的will-change屬性

青灯夜游
青灯夜游轉載
2021-06-28 11:14:484559瀏覽

什麼是css will-change屬性?要怎麼用?這篇文章就來帶大家研究一下will-change屬性,看看何時使用、如何使用以及如何更好的在css中設定will-change。

深入了解css中的will-change屬性

will-change

CSS 屬性will-change 為web開發者提供了一個告知瀏覽器該元素會有哪些變化的方法,這樣瀏覽器可以在元素屬性真正改變之前提前做好對應的最佳化準備。這種優化可以將一部分複雜的計算工作提前準備好,使頁面的反應更為快速靈敏。

重要提示:will-change 旨在用作嘗試處理現有的效能問題的最後手段。它不應該用於預測效能問題。

取代translateZ() Hack

#例如,當使用CSS 3D 變換(transform)在螢幕上移動元素時,元素及其內容可能會被提升到一個「層」(layer),在那裡它們可以獨立於頁面的其餘部分進行渲染,並在以後進行合成。這樣隔離了內容的呈現,如果元素的變換(transform)是在幀之間發生變化的唯一內容,則不必重新渲染頁面的其餘部分,並且通常提供顯著的速度優勢。

然而,在新層(layer)中設定元素是一項相對昂貴的操作,它可以將變換動畫的開始延遲明顯的幾分之一秒。

為了避免在使用CSS Transforms 和其他CSS 操作時出現這種延遲,我們長期以來一直使用translateZ(或有時是translate3d)將元素提升到它們自己的層,從而實現硬體加速操作,以運行更流暢、更快,沒有毛邊。然而,這種技巧——也被稱為「translateZ()(或 translate3d()) Hack」——是有代價的。保羅劉易斯寫了一篇關於這個的非常有用的帖子,如果你使用這種技術,你一定要檢查一下。 will-change 是為了讓我們能夠優化我們的動畫,而不必求助於這個 hack——或者任何其他 hack。

(學習影片分享:css影片教學

#逗號分隔

您可以透過指定您希望變更的屬性名稱(以逗號分隔)來向瀏覽器聲明您打算變更元素的捲動位置、其內容或其一個或多個CSS 屬性值。大多數屬性在指定時將不起作用,因為使用者代理程式不會對大多數屬性的變更執行任何特殊最佳化。不過,指定它們仍然是安全的,雖然根本沒有效果。

如果您期望或計劃更改元素的多個值/方面,您可以提供逗號分隔值的清單。逗號分隔值清單可以包括預先定義的關鍵字和/或屬性名稱。 (請參閱下面的範例部分。)

額外建立堆疊上下文和包含區塊

如果您聲明的屬性的任何非初始值會在元素上建立堆疊上下文,則在will-change 中指定該屬性一定在元素上建立堆疊上下文。例如,將 opacity 設定為 1 以外的任何值都會在元素上建立堆疊上下文。因此,設定 will-change: opacity 也會建立一個堆疊上下文,即使 opacity 目前仍然等於 1。

類似地,如果屬性的任何非初始值會導致元素為固定位置元素產生包含區塊,則在 will-change 中指定該屬性必須導致元素為固定位置元素產生包含區塊。

will-change 屬性對它指定的元素沒有直接影響,除了前面提到的創建堆疊上下文和包含塊之外——它只是對用戶代理的渲染提示,允許它在某些類型的更改實際開始發生之前設定潛在昂貴的最佳化。

謹慎使用

話雖如此,重要的是您知道應謹慎使用此屬性。不同的瀏覽器可以以不同的方式使用來自 will-change 的訊息,甚至單一瀏覽器也可能在不同的時間以不同的方式使用它。過度使用它可能會導致完全忽略聲明。例如,當元素有 will-change 時,將元素提升到它們自己的「GPU 層」的瀏覽器。但當有太多元素聲明時,瀏覽器將忽略聲明,以避免耗盡 GPU 記憶體。

此外,除非已知或預期元素會在不久的將來(例如,在幾分之一秒內)發生變化,否則不應使用 will-change。一旦不再需要它,就應該取消設定:

在實際更改的元素上將 will-change 設定為您將實際更改的屬性。並在他們停止時將其刪除。 - Tab Atkins Jr.(規範編輯者)

瀏覽器對即將發生的變更進行的最佳化通常代價高昂,而且正如我們前面提到的,會佔用非常多的機器資源。通常瀏覽器優化行為是刪除這些最佳化並儘快恢復到正常行為。然而,will-change 會涵蓋這種行為,保持優化的時間比瀏覽器其他場景更長。

因此,您應該始終記住在元素完成更改後刪除 will-change,以便瀏覽器可以恢復優化聲明的任何資源。

使用JavaScript 設定 will-change

#透過JavaScript 設定will-change 允許更細粒度的控制,和更多瀏覽器準備更改的時間,並且還允許您在動畫事件結束後立即取消設定。使用 JavaScript,您可以向瀏覽器聲明您的更改,然後在更改完成後透過監聽這些更改何時完成來刪除 will-change。

例如,您可以監聽元素(或其祖先)何時懸停,然後在 mouseenter 上設定 will-change。如果你的元素正在被動畫化,你可以使用 DOM 事件 animationEnd 監聽動畫何時結束,然後在 animationEnd 觸發後移除 will-change。

// Rough generic example
// Get the element that is going to be animated on click, for example
var el = document.getElementById('element');

// Set will-change when the element is hovered
el.addEventListener('mouseenter', hintBrowser);
el.addEventListener('animationEnd', removeHint);

function hintBrowser() {
	// The optimizable properties that are going to change
	// in the animation's keyframes block
	this.style.willChange = 'transform, opacity';
}

function removeHint() {
	this.style.willChange = 'auto';
}

更好的在css 中設定will-change

#如果您確實想在樣式表中設定will-change 以針對可能在懸停時更改的元素進行最佳化,那麼為了告訴瀏覽器針對您希望在懸停時發生的更改進行優化,您可以執行以下操作:

.el:hover {
    will-change: transform;
    transform: rotate()...;
}

這並不是特別錯誤,但也不是特別有用。您需要在更改實際發生之前的某個時間向瀏覽器聲明您的意圖,而不是在更改發生時,以便給它一些時間來準備更改並進行所需的優化。所以,在這樣的場景中,你可以這樣做:

.el {
    will-change: transform;
}

.el:hover {
    transform: rotate()...;
}

或者,您可以在元素的容器懸停時設定will-change,因為懸停事件到達元素本身需要一些時間,然後瀏覽器可以使用該時間為元素本身的更改做準備:

.container:hover .el {
    will-change: transform;
}

.el:hover {
    transform: rotate()...;
}

總結一下,記得謹慎使用will-change,不要過度使用,只有在知道元素即將改變時才設置它,並且記得在改變完成後取消設定。

官方語法

  • #「
will-change: auto | <animateable-feature>#

#
<animateable-feature> = scroll-position | contents | <custom-ident>

標籤(#) 表示您可以指定多個值,多個值以逗號分隔。

  • 初始值:auto
  • 適用於:所有元素
  • #動畫:否

值( Values)

auto

這是預設值。它沒有表達特別的意圖。瀏覽器不會收到任何更改的通知,因此不會進行任何優化以適應未來的任何更改。

scroll-position

表示作者希望在不久的將來動畫或更改元素的捲動位置。瀏覽器會提前針對此變更進行適當的最佳化。

例如,瀏覽器通常只在可滾動元素上呈現「滾動視窗」中的內容,以及已經經過該視窗的內容,從而平衡好跳過渲染所節省的時間和內存,以使滾動看起來更好看。瀏覽器可能會將此值作為訊號來擴展呈現的滾動視窗周圍的內容範圍,以便可以平滑地完成更長/更快的捲動。

contents

表示作者希望在不久的將來動畫或更改元素內容的某些內容。瀏覽器會提前針對此變更進行適當的最佳化。

例如,瀏覽器經常會隨著時間的推移「快取」元素的渲染,因為大多數東西不會經常改變,或者只是改變它們的位置。但是,如果元素確實定期更改其內容,那么生成和維護此快取就是浪費時間。瀏覽器可能會將這個值作為一個信號,在元素上不那麼積極地緩存,或者根本避免緩存而只是不斷地從頭開始重新渲染元素。

e53daba18c25ef518ad73d82fe4f7af3 (028aa264268b1d80e0a56150adf879cc)

36c67616b8eb707f2ee13847ef0d2ea4 值(有關詳細信息,請參閱e53daba18c25ef518ad73d82fe4f7af3 條目)。表示作者希望在不久的將來對元素上具有給定名稱的屬性進行動畫處理或更改。

例如,瀏覽器通常會將設定有非初始值transform 屬性的元素和其他元素區分開,可能將它們渲染到自己的“GPU 層”,或使用其他機制來更容易的快速的進行變換。瀏覽器可能會將transform 的值作為一個訊號,表示它應該在元素開始轉換之前立即將元素提升到它自己的圖層,以避免重新渲染舊圖層和新圖層所涉及的任何延遲。

除了通常从 e53daba18c25ef518ad73d82fe4f7af3 中排除的关键字之外,e53daba18c25ef518ad73d82fe4f7af3 值不能是以下关键字之一:will-changenoneallautoscroll-positioncontents

请注意,大多数属性在指定时将不起作用,因为用户代理不会对大多数属性的更改执行任何特殊优化。不过,指定它们仍然是安全的,虽然它根本没有效果。

注:感觉虽然命名为『自定义标志』, 其实主要碰到的还是 css 预定义好的标志,譬如 transform、opacity

例子

下面告诉浏览器期望元素的变换属性发生变化,以便提前进行适当的优化。

.el {
    will-change: transform;
}

上面的 will-change 声明应该通过 JavaScript 添加,然后在更改结束后删除或取消设置 (will-change: auto)。

以下所有的都是可能且有效的 will-change 值:

will-change: contents;
will-change: scroll-position;
will-change: opacity;/* multiple comma-separated values */will-change: contents, transform;
will-change: scroll-position, opacity;

使用小结

想使用好 will-change 并不是太容易,以下使用忠告摘录于官方文档,可见真是太难了。

  • 不要将 will-change 应用到太多元素上: 浏览器已经尽力尝试去优化一切可以优化的东西了。有一些更强力的优化,如果与 will-change 结合在一起的话,有可能会消耗很多机器资源,如果过度使用的话,可能导致页面响应缓慢或者消耗非常多的资源。

  • 有节制地使用: 通常,当元素恢复到初始状态时,浏览器会丢弃掉之前做的优化工作。但是如果直接在样式表中显式声明了 will-change 属性,则表示目标元素可能会经常变化,浏览器会将优化工作保存得比之前更久。所以最佳实践是当元素变化之前和之后通过脚本来切换 will-change 的值。

  • 不要过早应用 will-change 优化: 如果你的页面在性能方面没什么问题,则不要添加 will-change 属性来榨取一丁点的速度。 will-change 的设计初衷是作为最后的优化手段,用来尝试解决现有的性能问题。它不应该被用来预防性能问题。过度使用 will-change 会导致大量的内存占用,并会导致更复杂的渲染过程,因为浏览器会试图准备可能存在的变化过程。这会导致更严重的性能问题。

  • 给它足够的工作时间准备,不要过迟应用: 这个属性是用来让页面开发者告知浏览器哪些属性可能会变化的。然后浏览器可以选择在变化发生前提前去做一些优化工作。所以给浏览器一点时间去真正做这些优化工作是非常重要的。使用时需要尝试去找到一些方法提前一定时间获知元素可能发生的变化,然后为它加上 will-change 属性。

更多编程相关知识,请访问:编程视频!!

以上是深入了解css中的will-change屬性的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除