多數人以為,網站的 Core Web Vitals 分數掉了,兇手就是那些讓人眼睛一亮的動態特效,像是按鈕按下去的縮放回饋、頁籤切換的滑動轉場、載入時的漸層過場。但 Core Web Vitals 量的是三件具體的事:最大內容繪製(LCP,目標在頁面開始載入後 2.5 秒內完成)、互動反應速度(INP,目標低於 200 毫秒)、視覺穩定度(CLS,目標低於 0.1)。這三者跟「畫面上有沒有動態效果」不是同一回事,跟「這個動態效果用什麼方式做出來、有沒有擋到內容與互動」才是同一回事。
這個誤判帶來的後果不小。不少團隊一看到 Core Web Vitals 報表亮紅燈,第一個反應就是把動態特效整批拔掉,以為「乾淨的靜態頁面」等於「安全牌」,結果賠上的是品牌個性與使用者對操作的回饋感。該做的是逐一看每個動態特效碰到哪個指標:用 width、height、top、left 這類會改變版面幾何的屬性跑動畫,可能同時拖累 INP 與 CLS;擋在首屏主視覺前面的進場動畫,會拖慢 LCP;只動 transform 與 opacity 的效果,多半不必為分數讓步。

「動態特效拖累效能」這個說法,把因果關係說反了
把「有動態特效」跟「分數差」直接畫上等號,是把因果關係說反了。問題從來不是有沒有動畫,而是這個動畫用哪個屬性、跑在哪條執行緒上。
最常見的地雷寫法是直接改變元素的幾何屬性做動畫,像是用 width、height 做展開收合效果,或用 top、left 做位移。這類屬性一旦改變,瀏覽器就得重新計算這個元素、以及可能連帶被推移的其他元素的位置與大小,這道程序叫版面配置(layout),算完還要重新繪製(paint)。版面配置與繪製都吃主執行緒資源,動畫每一格都要重算一次,幀率自然掉,使用者也會感覺到卡頓。Google 的 web.dev 效能指南建議動畫維持每秒 60 幀,低於這個幀率,使用者就會察覺到卡頓或停頓。
換成 transform 與 opacity 這兩個屬性做同一件事,結果完全不同。位移改用 transform: translate、縮放改用 transform: scale、淡入淡出改用 opacity,瀏覽器不需要重新計算版面配置,也幾乎不用重新繪製,兩者能讓瀏覽器做高度最佳化的處理。這個判準不分 JavaScript 驅動或純 CSS 驅動的動畫都適用。差別從來不在「有沒有動」,而在「動的是哪個屬性」。
問題不在「該不該有動態特效」,而在「怎麼判斷這個動態特效該不該讓步給指標」。先弄清楚動態特效跑在哪裡、佔用了誰的資源,才有辦法回答後面那個更實際的問題。
合成器執行緒讓動態特效不必等主執行緒讓路
瀏覽器把動態特效跑在哪裡,決定了它會不會跟頁面互動搶資源。
依 web.dev 的說明,CSS 動畫與瀏覽器原生的 Web Animations,通常會交給「合成器執行緒」處理,這條執行緒跟負責樣式計算、版面配置、繪製、執行 JavaScript 的「主執行緒」是分開的兩條路。當主執行緒正忙著回應使用者輸入或跑一大段 JavaScript 時,跑在合成器執行緒上的動態特效仍然能繼續播放,不會被打斷、也不會反過來拖慢主執行緒的工作。transform 與 opacity 這兩個屬性,多數情況下正好能單獨交由合成器處理,不需要主執行緒插手。

這個分工跟兩個核心指標的定義接起來,問題就更清楚了。INP 量的是「使用者互動到瀏覽器完成下一次繪製」之間的時間,量測範圍是使用者造訪這個頁面期間的所有互動,不只算第一次;Google 在 web.dev 公告,INP 已在 2024 年 3 月 12 日正式取代 FID 成為 Core Web Vitals 指標之一,取代的原因正是 FID 只看首次互動,漏掉了使用者實際體驗到的其他互動延遲。CLS 量的是視覺穩定度,看的是元素有沒有無預期的位移。這兩個指標量的都是「使用者互動有沒有被拖延」與「畫面有沒有無預期跳動」,跟畫面上存不存在動態效果無關,只跟這個動態特效有沒有霸佔主執行緒有關。
換句話說,「動態特效正在播放」這件事本身不會直接等於「INP 變差」。INP 分數不佳最常見的成因,是主執行緒被長時間工作佔用、DOM 過於龐大、CSS 選擇器過於複雜、或用戶端要處理大量的 HTML 渲染。這些原因裡沒有一項是「畫面上有動態效果」本身,而是動態特效若用了非合成器屬性、或在互動當下觸發大量運算,才會加重這些既有問題。
一段拿捏得宜的載入動態特效讓等待感覺變短
Core Web Vitals 量的是機器可測的毫秒與分數,但使用者評估「這個網站快不快」用的是主觀感受,兩者不完全是同一件事。
一份發表於歐洲認知人因工程學會議、收錄於 ACM Digital Library 的研究,直接對比了兩種載入態呈現方式:一種是傳統的載入圈圈(spinner),另一種是先用頁面骨架佔位、內容陸續填入的 skeleton screen。結果顯示,使用 skeleton screen 的網頁在「感受到的回應速度」與「導覽的容易程度」這兩項評分上,平均都高於使用 spinner 的版本。這個發現支撐了一個容易被忽略的事實:載入態動態特效不只是裝飾,它會實際影響使用者對「這個網站快不快」的判斷,跟機器測到的真實載入時間是兩條可以分開討論的線。
這裡可以順勢把 INP 的定義跟這個發現接起來看。INP 本質上量的就是「使用者互動之後,多快得到瀏覽器的下一次視覺回饋」,而一段節奏拿捏得當的過場動態特效,某種程度上正是在管理這個回饋節奏,讓使用者在等待資料回來之前,先看到畫面有在回應他的操作,而不是面對一片空白或一顆不知道還要轉多久的圈圈。這麼看,動態特效可以是回饋機制的一部分,不只是視覺上的加分項,前提仍然是它跑在合成器執行緒、不佔用主執行緒的運算資源。
Core Web Vitals 只是排名系統眾多考量之一
Google 官方對 Core Web Vitals 的定位講得很明白:核心排名系統會綜合參考多種與整體網頁體驗一致的訊號,並沒有單一的「網頁體驗訊號」決定排名;即使某個頁面的網頁體驗不夠好,Google Search 仍會優先顯示最相關的內容。內容相關性與品質仍然是主要判準,Core Web Vitals 只是眾多考量因素裡的一項,不是唯一或絕對的門檻。
從這個定位往下推,把「某個動態特效讓 INP 差了 20 毫秒」當成末日級的問題,等於把一個排名考量因素裡的一小部分,錯當成唯一標準。過度反應同樣是問題。為了追求滿分把所有動態效果、所有視覺回饋一律拔除,犧牲掉的可用性與品牌感受,不見得換得回等值的排名收益。
這個判斷還可以再往下延伸一層,拉進業務脈絡來看。對不主要靠自然搜尋流量導流的頁面,例如活動宣傳頁、廣告到達頁、或需要登入才看得到的產品內頁,Core Web Vitals 對整體業務目標的邊際影響本來就有限,把使用體驗放在分數前面是合理的資源分配。但這不是放棄效能紀律的藉口。基本的可用性,尤其是下一節要談的「尊重使用者的減少動態偏好」,仍然不能省,那已經不只是排名考量,而是對使用者的基本尊重。
忽略「減少動態」偏好,才是動態特效該被檢討的地方
動態特效真正該被檢討的理由,不是幀率,而是有沒有尊重使用者在系統層級設定的偏好。prefers-reduced-motion 讓有前庭功能障礙、動暈敏感的使用者,能在作業系統層級要求網頁減少動態效果,web.dev 的說明指出,對這群使用者來說,視差捲動這類動畫可能引發暈眩、噁心,減少動畫是醫療上的必要,不是美感偏好;靠 JavaScript 驅動的輪播、計時轉場也該一併照顧,不能因為不是 CSS 動畫就當作例外。這件事跟 Core Web Vitals 是兩條線,一個動態特效可以完全不拖累 INP、不影響 CLS,卻仍然讓特定使用者不舒服,所以該先問「這個使用者需不需要、想不想要」,再問「分數會不會掉」。
這幾種情況該讓指標贏過動態特效
前面幾節談的是「動態特效不必然拖累指標」,但這不代表動態特效永遠不用讓步。以下三個情境,分別對應 LCP、INP、CLS 三大指標各自最容易被動態特效拖累的場景,該讓指標贏的時候,就該讓。

最大內容還沒登場前,動態特效不能擋在它前面
LCP 量的是「頁面開始載入後,多快看到最大內容元素」,目標是在 2.5 秒內完成。如果首屏的最大內容元素,像是一張大圖或主標題,本身要等一段淡入效果、打字機效果、或延遲觸發的進場動畫跑完,才算「視覺上完成呈現」,等於自己拖慢了 LCP 判定的時間點。
這種情境沒有太多模糊空間可以討論。凡是動態特效直接包住、或延遲了 LCP 候選元素本身的最終呈現,就該拿掉,或者改成不延遲首次呈現的寫法,讓這個元素先以完整樣貌出現,動態特效只做次要的裝飾層,疊加在已經呈現完成的內容之上,而不是擋在內容前面。判斷依據就是 LCP 的定義本身,量的是最大內容元素何時視覺上完成呈現,不需要額外數據佐證,先看一眼這個元素有沒有被動態特效延遲呈現就夠了。
互動回應逼近門檻時先讓主執行緒喘口氣
這個情境對應 INP。當 PageSpeed Insights 或 CrUX 這類欄位資料顯示,網站的 INP 已經逼近、甚至落在「需要改善」或「不佳」的區間,目標門檻是低於 200 毫秒,這時任何會佔用主執行緒的動態特效,尤其是牽動版面配置或繪製的寫法、或是在互動發生的當下才執行大量 JavaScript 運算的動態特效,都該優先關掉或簡化,等 INP 回到「良好」區間,再考慮要不要加回來。
這本質上是資源排序的問題。INP 分數依據的是欄位資料在所有頁面載入中第 75 個百分位數的表現,代表的是多數使用者的實際體感;而 INP 表現不佳最常見的成因,包括主執行緒被長時間工作佔用、大型 DOM 需要大量渲染、CSS 選擇器過於複雜、用戶端渲染 HTML 的比重過高。這些既有負擔若再疊上一個佔主執行緒的動態特效,只會讓情況更糟。主執行緒的餘裕有限,先保障「使用者點下去多快有反應」,裝飾性的動態特效排在後面才合理。
牽動大量版面重排的轉場,先簡化流程再談效果
這個情境對應 CLS。頁籤切換、卡片展開、篩選結果更新,這類會讓大量元素重新排列的轉場,如果動畫走的是會觸發版面配置的屬性,例如直接改變元素的 width、height、margin 讓周圍其他元素跟著被推移,使用者就會在畫面上看到明顯的跳動或位移,這正是 CLS 要量測的視覺不穩定,目標是低於 0.1。依 web.dev 對 CLS 的定義,使用者操作後 500 毫秒內發生的位移可以不計入,但轉場動畫拖過這段時間、或結果晚一步才補進來把版面推開,後續的位移就會被算進去。
只有 transform 與 opacity 能單純交由合成器處理,改變其他會影響元素幾何的屬性,會連帶讓頁面上其他元素被迫重新排列,這正是版面配置的觸發條件,也是 CLS 分數變差的直接成因。這種情境的正確做法不是把轉場整個拿掉,而是先把版面重排的邏輯簡化,例如固定容器尺寸、用 transform 位移取代直接改變幾何屬性,讓視覺效果建立在不觸發版面配置的寫法上。做不到這一步之前,先讓轉場退回瞬間切換,別讓「效果好不好看」的優先順序,排在「畫面穩不穩」前面。
把這三個情境放在一起看,會發現它們共通的判準其實很一致,不是問「這個動態特效好不好看」,而是問「它是不是擋在關鍵內容前面、佔用了正在被使用者需要的主執行緒、或製造了看得見的版面跳動」。答案是的話,先讓指標贏;答案不是,動態特效沒有理由被當成代罪羔羊拿掉。分數與體驗從來不是天生對立的兩端,拖垮分數的從來是寫法,不是動態特效這件事本身——先把因果關係擺正,才有辦法在每一個具體場景裡,做出真正該做的取捨。
