你正在讀一篇文章,讀到一半,整段內容突然往下跳了一截,原本要點的按鈕也跑掉了——這種「畫面自己亂動」的體驗,背後就是 CLS 太高。CLS(Cumulative Layout Shift,累積版面位移)是 Google 三項核心網頁指標之一,量的是頁面在載入與瀏覽過程中,元素非預期移動的累積幅度。它不只惹惱訪客,還是搜尋排名的評分項目,分數差會連帶拖累 SEO。
WordPress 站特別容易踩到這個雷,因為佈景主題、外掛、廣告碼、外部嵌入各自把內容塞進頁面,誰先載入、誰後載入很難控制。這篇談的不是泛泛的「記得加圖片尺寸」,而是 WordPress CLS 優化的實戰拆解:怎麼定位是哪個元素在位移、圖片與影片該怎麼鎖尺寸、廣告位與 iframe 怎麼預留空間、字型造成的位移怎麼用 fallback 字型 metric 補正,以及外掛動態插入區塊該如何處理。每一段都附上可直接套用的做法。
CLS 是什麼,分數到多少才算及格
先把標準講清楚:CLS 分數在 0.1 以下算「良好」,0.1 到 0.25 之間是「需要改善」,超過 0.25 就是「差」。Google 要求至少 75% 的頁面瀏覽達到 0.1 以下,這個門檻同時適用於行動版與桌機版,而行動版通常更難達標,因為螢幕小、網路與處理器條件較差,元素一移動相對位移比例就被放大。
CLS 和其他兩項核心指標不一樣,它沒有單位。LCP(最大內容繪製)量的是秒數、INP 量的是毫秒,CLS 則是把「位移影響的視窗比例」乘上「元素移動的距離比例」,再把整個頁面生命週期內所有非預期位移加總起來的一個純數值。
關鍵在「非預期」三個字。如果位移是使用者主動操作觸發的——例如點了「展開更多」按鈕後內容才撐開——而且發生在互動後 500 毫秒內,這類位移會被視為預期行為,不計入 CLS。會被算進去的,是訪客沒做任何動作、頁面卻自己跳動的那些。
怎麼找出是哪個元素在位移
優化前先診斷,不要憑感覺亂改。最容易誤判的地方是:實驗室數據(Lab)和真實使用者場域數據(Field)對不上。
PageSpeed Insights 同時提供兩種數據。Field 數據來自 Chrome 使用者體驗報告(CrUX),是真實訪客的數字,也是 Google 拿來當排名訊號的那一份;Lab 數據則是 Lighthouse 模擬一次頁面載入跑出來的。兩者常常不一致,原因是 Lab 只量「頁面初始載入期間」的位移,而 Field 量的是訪客從進站到離站「整個瀏覽過程」的位移。所以如果 DevTools 跑出來 CLS 是 0,CrUX 卻顯示很差,多半是位移發生在載入完成之後——例如捲到一半才載入的廣告、延遲彈出的訂閱框。
要看「到底是哪個元素」在動,有三個層次的工具。最快的是 PageSpeed Insights 報告裡的「避免大幅度的版面配置位移」診斷項,展開後會列出貢獻最多位移的 DOM 元素,並標出各自的位移分數,先修分數最高的那幾個通常就能過關。
想看得更直觀,用 Chrome DevTools 的 Rendering 面板。打開 DevTools 後點右上角三點選單,選「More Tools → Rendering」,勾選「Layout Shift Regions」,再重新整理頁面,發生位移的區域會在載入時用藍框閃一下標出來。閃太快看不清楚就配合 Performance 面板逐影格檢視。
想一次掃全站,用 Google Search Console 的核心網頁指標報告。它依 CrUX 真實數據把出問題的網址分群列出,修好一類就能批次驗證所有同因網址,比一頁一頁測效率高很多。前提是站台流量要足以被納入 CrUX 報告。
圖片與影片怎麼鎖住尺寸
最常見的位移來源就是沒指定尺寸的圖片與影片。瀏覽器不知道要預留多大空間,先用一個猜測值排版,等圖片真正載入、實際尺寸比預留的大,已經顯示的內容就被往下擠。
解法是在 <img> 與 <video> 標籤上明確寫出 width 與 height 屬性。瀏覽器拿到這兩個值,會先依長寬比把空間留好,圖片載入時就不需要再推動其他內容。一張 600×300 的圖長這樣:
<img src="example.jpg" alt="範例圖片" width="600" height="300">
好消息是:透過 WordPress 區塊編輯器、傳統編輯器,或 Elementor、Divi、Beaver Builder 這類頁面建構器插入的圖片,WordPress 預設會自動補上尺寸屬性,這部分通常不用你操心。會出問題的是「手動嵌入」的圖片——你在子主題的範本檔裡自己寫 <img>、在外掛輸出裡塞圖、或從外部來源拉圖時忘了帶尺寸。這些地方要逐一補齊。
響應式圖片用 srcset 提供多種解析度時,仍然要寫 width 與 height,而且整組圖必須維持相同長寬比,瀏覽器才能正確算出預留空間:
<img width="1000" height="1000"
src="puppy-1000.jpg"
srcset="puppy-1000.jpg 1000w, puppy-2000.jpg 2000w"
alt="範例圖片">
另一種寫法是搭配 CSS 的 aspect-ratio。只要給出 width 或 height 其中一個,再用 CSS 設定長寬比,瀏覽器就能在渲染前推算出缺的那一邊、預留正確空間。很多 YouTube 嵌入外掛就是用 aspect-ratio 來輸出影片框,原理相同。
廣告位的空間怎麼預留
廣告是 WordPress CLS 優化裡最棘手的一塊,因為它幾乎一定是延遲載入。只要用到競價技術,系統需要時間決定要顯示哪一支廣告;AdSense 自動廣告若開了動態廣告版位,連尺寸都可能事先不知道,回傳的廣告大小還會變來變去。空間沒先留好,廣告一進來就把內容往下推。
核心原則是:在廣告碼外層包一個容器,用 CSS 的 min-height 把空間先撐住,就算廣告還沒載入、甚至最後是空的,版面也不會塌。Google 的建議是把 min-height 設成「該版位可能出現的最大廣告尺寸」,雖然遇到小廣告時會留白浪費一點空間,但這是最能徹底消除位移的做法。
這裡有一個容易踩的細節:包廣告的容器要用 CSS ID 來指定樣式,不要用 class。因為 AdSense 經常會把父層物件的 class 屬性剝掉,用 class 寫的 min-height 會失效。寫法像這樣:
<div id="ad-slot-top" style="min-height:280px;"></div>
不同裝置的廣告尺寸不一樣,桌機可能是大橫幅、行動版是方塊,這時用媒體查詢針對不同螢幕寬度給不同的 min-height,避免行動版預留過頭、桌機又留不夠。
如果你用的是 Mediavine、AdThrive 這類廣告聯播網,它們後台多半內建了 CLS 優化開關,把對應選項打開即可,不必自己手刻容器。另外,盡量別把會浮動的廣告放在首屏最頂端,非黏性廣告擺到頁面中段、遠離視窗頂部,就算晚載入也不會把首屏內容整個推走。
嵌入內容與 iframe 怎麼處理
影片、地圖、社群貼文這類 iframe 嵌入,和圖片是同一套邏輯:沒指定尺寸就會位移。多數服務的官方嵌入碼本身就帶了 height 與 width,例如 YouTube 的嵌入碼裡就含尺寸,這種直接貼上就好。
問題出在嵌入碼沒帶尺寸的情況。這時手動把 width 與 height 補進 iframe 標籤,或在外層容器用 aspect-ratio 把比例鎖住。遇到事先無法確定尺寸的嵌入內容,做法和廣告一樣——放一個固定尺寸的佔位元素或 fallback 區塊,先把空間佔住,內容載進來時就有地方安放,不會去推動旁邊已經顯示的東西。
網頁字型造成的位移怎麼補正
字型是 WordPress 站常被忽略的位移源頭,分成兩種狀況。一種是 FOIT(Flash of Invisible Text),自訂字型還沒載入時整段文字隱形,字型一到文字才突然出現,把內容撐開。另一種是 FOUT(Flash of Unstyled Text),先用系統字型把文字顯示出來,自訂字型載入後再換掉——換字的瞬間,因為兩套字型的字寬、行高不同,內容跟著位移。
第一步是設定 CSS 的 font-display。用 swap 會讓瀏覽器先用 fallback 字型把文字顯示出來、自訂字型載好再換,徹底解決 FOIT;用 optional 則讓瀏覽器只給自訂字型約 100 毫秒的載入機會,逾時就整頁沿用 fallback 字型、這次瀏覽不再換字,連 FOUT 都一併避開,代價是訪客首次瀏覽可能看不到你的品牌字型。
第二步是把字型本地代管並 preload。把字型檔放在自己的伺服器、用 rel="preload" 提高它的載入優先順序,讓字型趕在主要內容渲染前就備妥,FOUT 與 FOIT 的發生機率都會降低:
<link rel="preload" href="/fonts/roboto.woff2" as="font" type="font/woff2" crossorigin>
字型格式優先用 WOFF2,它比 WOFF 與 SVG 大約再小三成,WOFF 留作舊瀏覽器的後備即可。
真正能把字型位移壓到接近零、而多數 WordPress 教學沒講到的,是第三步:調整 fallback 字型的 metric,讓它的佔位面積盡量貼近自訂字型。就算用了 swap 加上挑過的 fallback 字型,只要兩套字型的字身比例有差,換字時還是會有小位移。做法是另外為 fallback 字型寫一條 @font-face 規則,用 size-adjust、ascent-override、descent-override 三個描述子去縮放與校正它的高度比例。
要拿到自訂字型的 metric 數值,可以用 Capsize 這類工具上傳字型檔,讀出它的 Ascender、Descender 與 Em Square 值,再換算成百分比填進規則裡:
@font-face {
font-family: "fallback-adjusted";
src: local("Arial");
size-adjust: 105%;
ascent-override: 110%;
descent-override: 25%;
}
.body-text {
font-family: "品牌字型", "fallback-adjusted", sans-serif;
}
不想手算,市面上有 fallback 字型產生器提供視覺化介面,調到 fallback 與自訂字型疊合得幾乎一樣就行。挑 fallback 字型本身也有講究:等寬字型的 fallback 要選等寬系統字(例如 Courier New),無襯線配無襯線,先讓兩者大方向接近,再用 metric 描述子做微調,位移會小很多。
如果這套流程對你太繁瑣,還有一個一勞永逸的選項——直接用系統字型堆疊(system font stack),完全不載自訂字型。這會犧牲一些設計自由度,但字型造成的位移、FOIT、FOUT 一次全部消失,頁面也載得更快。
外掛動態插入的內容與動畫怎麼控制
很多 WordPress 站會靠外掛在頁面上動態塞東西:cookie 同意條、相關文章、訂閱表單、A/B 測試腳本。這些本身沒問題,問題在於塞的「位置」與「時機」。
一條好用的原則是:除非是使用者主動操作觸發,否則不要把內容插在既有內容的上方。例如 cookie 同意條若插在頁面最頂端,會把整頁內容往下推;改成貼在頁面底部,就不會推動任何已顯示的內容。真的要放在上方,就得事先替它預留好空間。
要確認是不是某支外掛在搞鬼,回頭用前面提到的視覺化工具——Layout Shift Regions 或位移 GIF 產生器——看藍框閃在哪個區塊,再對照是哪支外掛輸出的。找到元凶後,調整該外掛的設定,或換一支對 CLS 友善的同類外掛。不同的 cookie 同意外掛在這方面表現差很多,值得實測比較。
動畫也是常見的位移源頭。如果用 height、width、top、left 這類會觸發重新排版的屬性做動畫,每一影格都可能算進 CLS。改用 CSS 的 transform——例如 transform: scale() 取代改寬高、transform: translate() 取代改位置——這類屬性由合成器層處理,不會觸發版面重排,自然不會產生位移。
修完之後,怎麼確認真的有效
把上面幾類問題逐一處理完,別只在自己電腦上看一眼 Lighthouse 就收工。本機 Lab 數據只反映一次載入,真正決定排名的是 CrUX 的場域數據,而 CrUX 有約 28 天的資料延遲,改動要過一陣子才會反映在真實使用者的數字上。
務實的節奏是:先用 PageSpeed Insights 與 DevTools 的 Layout Shift Regions 確認 Lab 端位移已歸零,把該鎖的尺寸、該預留的空間、該補正的字型都處理好,再回到 Search Console 的核心網頁指標報告按「驗證修正」,讓 Google 重新評估同因網址那一群。之後持續觀察 CrUX 的行動版數字——行動版才是最難達標、也最影響排名的戰場。把圖片、廣告位、嵌入、字型、動態插入這幾個源頭一個個鎖死,CLS 自然會穩定落在 0.1 以下,訪客不再被亂跳的畫面打斷,搜尋引擎也會把這份穩定算進你的分數裡。