Fix CLS: luôn set width/height trên images/videos, reserve space cho dynamic content, dùng font-display: swap với size-adjust, dùng transform thay vì top/margin cho animations.
- CLS đo mức độ layout shift unexpected trong quá trình loading — score là sum của (impact fraction * distance fraction) cho mỗi shift.
- Target <0.1; >0.25 là poor.
- Nguyên nhân phổ biến và fix: Images/videos không có dimensions — luôn set width/height attributes (aspect-ratio CSS tự tính) hoặc dùng aspect-ratio: 16/9 container; browser reserve space trước khi image load.
- Fonts gây FOUT (Flash of Unstyled Text) khi web font load — dùng font-display: swap với size-adjust để match fallback font metrics; font-display: optional skip web font nếu không cached (zero CLS nhưng có thể không dùng web font); preload critical fonts.
- Dynamically injected content (banners, cookie notices, ads) shift content — reserve space trước bằng min-height container; không inject content above existing content sau page load.
- Dynamic ads: Google Ads có thể gây CLS — fix bằng reserve fixed space cho ad slot.
- Infinite scroll: thêm items dưới thay vì trên viewport. transform: translateY() thay vì top/margin cho animations — transform không trigger layout.
- CLS sau interaction (300ms window) không tính vào score — UX vẫn tệ nhưng không penalty.
- Debugging: Chrome DevTools Performance panel, Layout Shift Regions (Rendering tab).
Fix CLS: always set width/height on images/videos, reserve space for dynamic content, use font-display: swap with size-adjust, use transform instead of top/margin for animations.
- CLS measures unexpected layout shifts during page load — the score is the sum of (impact fraction * distance fraction) for each shift.
- Target <0.1; >0.25 is poor.
- Common causes and fixes: Images/videos without dimensions — always set width and height attributes (CSS aspect-ratio calculates automatically) or use an aspect-ratio: 16/9 container; the browser reserves space before the image loads.
- Fonts causing FOUT (Flash of Unstyled Text) when web fonts load — use font-display: swap with size-adjust to match fallback font metrics; font-display: optional skips the web font if not cached (zero CLS but the web font may not be used); preload critical fonts.
- Dynamically injected content (banners, cookie notices, ads) shifts content — reserve space with a min-height container in advance; never inject content above existing content after page load.
- Dynamic ads: Google Ads can cause CLS — fix by reserving a fixed space for the ad slot.
- Infinite scroll: append items below, not above the viewport.
- Use transform: translateY() instead of top/margin for animations — transforms do not trigger layout.
- CLS after an interaction (300ms window) does not count toward the score — UX is still poor but there is no penalty.
- Debugging: Chrome DevTools Performance panel, Layout Shift Regions (Rendering tab).