CLS: trang nhảy khi đang đọc, năm nguyên nhân và cách giữ chỗ cho từng thứ
CLS (Cumulative Layout Shift) đo mức nội dung trên trang bị xô lệch bất ngờ khi đang hiển thị. Dưới 0,1 là tốt. Cách sửa chung cho mọi nguyên nhân là giữ chỗ trước: biết trước thứ gì sẽ xuất hiện thì dành sẵn khoảng trống cho nó.

Bạn đang đọc dòng thứ ba của bài viết, một quảng cáo tải xong ở phía trên và đẩy cả đoạn văn xuống, mắt bạn mất chỗ đang đọc. Bạn định bấm “Xem chi tiết”, một banner khuyến mãi chèn vào, ngón tay bấm trúng nút “Mua ngay” của sản phẩm khác. Hiện tượng này có chỉ số riêng: CLS (Cumulative Layout Shift), một trong ba chỉ số Core Web Vitals của Google, đo tổng mức xô lệch bố cục bất ngờ trong lúc trang hiển thị. CLS không đo bằng giây mà bằng một con số không đơn vị: dưới 0,1 là tốt, 0,1–0,25 cần cải thiện, trên 0,25 là kém.
CLS được tính thế nào
Mỗi lần một phần tử nhìn thấy được bị dời chỗ mà không do người dùng gây ra, trình duyệt tính điểm xô lệch bằng tích của hai thứ: phần màn hình bị ảnh hưởng và khoảng cách bị dời. Các lần xô lệch gần nhau được gom thành một “cửa sổ”, và CLS là cửa sổ tệ nhất trong suốt lượt xem trang.
Hai điểm quan trọng để không sửa nhầm:
- Xô lệch do người dùng gây ra không tính, nếu xảy ra trong vòng 500 mili giây sau khi họ bấm hoặc gõ. Bấm “Xem thêm” rồi nội dung mở ra là bình thường.
- Hiệu ứng bằng
transformkhông tính. Phần tử trượt vào bằng CSS transform không làm dời bố cục các phần tử khác. Hiệu ứng đổitop,margin,heightthì có tính.
Năm nguyên nhân và cách sửa
| Nguyên nhân | Dấu hiệu | Cách sửa |
|---|---|---|
| Ảnh, video, iframe không khai kích thước | Chữ hiện trước, ảnh về thì chữ bị đẩy xuống | Ghi width và height hoặc dùng aspect-ratio trong CSS |
| Quảng cáo, khối nhúng tải sau | Khoảng trống bỗng mở rộng giữa bài | Dành sẵn chiều cao tối thiểu cho vị trí quảng cáo |
| Banner chèn trên đầu trang (khuyến mãi, cookie, tải ứng dụng) | Cả trang bị đẩy xuống vài giây sau khi tải | Đặt banner nổi (cố định đáy hoặc lớp phủ), hoặc dành chỗ từ đầu |
| Font web tải chậm | Chữ nhảy cỡ, xuống dòng khác khi font thật về | Font dự phòng có số đo gần giống, font-display hợp lý, tải trước font chính |
| Nội dung tải bằng JavaScript sau khi hiện trang | Khối “sản phẩm liên quan”, giá, đánh giá chèn vào giữa | Dựng khung giữ chỗ cùng kích thước, hoặc dựng sẵn từ máy chủ |
Ảnh và video: giữ chỗ bằng tỉ lệ
Đây là nguyên nhân phổ biến nhất và dễ sửa nhất. Mọi thẻ <img>, <video>, <iframe> cần kích thước:
<img src="/anh/sofa-800.webp" width="800" height="533" alt="...">
<!-- Video YouTube nhúng: giữ tỉ lệ 16:9 -->
<iframe src="https://www.youtube.com/embed/..." width="560" height="315"
style="width:100%;height:auto;aspect-ratio:16/9" loading="lazy"></iframe>
Kết hợp với CSS img{max-width:100%;height:auto}, ảnh vẫn co giãn theo màn hình mà trình duyệt biết trước chiều cao. Ảnh trong bài viết WordPress chèn qua trình soạn thảo thường có sẵn kích thước; ảnh trong khối của page builder, ảnh sản phẩm trong giao diện tự viết thì hay thiếu. Chi tiết ở tối ưu ảnh cho tốc độ.
Quảng cáo và khối nhúng: dành chỗ trước
Site tin tức, blog có quảng cáo hiển thị chịu CLS nặng nhất, vì quảng cáo tải sau và cỡ thay đổi theo từng lượt đấu giá. Cách làm:
- Đặt
min-heightcho từng vị trí quảng cáo bằng cỡ phổ biến nhất của vị trí đó (ví dụ 250 điểm cho khối 300×250). - Không đặt quảng cáo ở sát đầu nội dung chính; vị trí càng cao, xô lệch càng ảnh hưởng nhiều phần màn hình.
- Khi không có quảng cáo để hiện, giữ khoảng trống thay vì thu lại về 0 (thu lại cũng là xô lệch).
- Khối nhúng Facebook, TikTok, bản đồ: bọc trong khung có chiều cao cố định.
Banner và thanh thông báo
Thanh “Miễn phí vận chuyển đơn từ 500k” chèn lên đầu trang sau khi kịch bản tải xong, banner xin đồng ý cookie đẩy nội dung xuống, thanh “Tải ứng dụng” trên điện thoại: mỗi cái là một lần cả trang bị đẩy. Ba cách:
- Dựng sẵn trong HTML nếu nó luôn hiện, để nó có mặt từ khung hình đầu tiên.
- Nổi lên trên nội dung (vị trí cố định ở đáy màn hình) thay vì chèn vào dòng chảy của trang.
- Dành chỗ bằng một khung trống cùng chiều cao nếu buộc phải chèn sau.
Lưu ý thêm: cửa sổ bật lên che toàn bộ nội dung trên điện thoại ngay khi vào trang còn là vấn đề trải nghiệm riêng Google không thích, ngoài chuyện CLS. Xem lập chỉ mục ưu tiên di động.

Font tiếng Việt: chữ nhảy khi font thật về
Site dùng font web (Be Vietnam Pro, Inter, Roboto từ Google Fonts hoặc tự lưu) thường hiện chữ bằng font hệ thống trước, rồi đổi sang font web khi tải xong. Hai font có độ rộng chữ khác nhau nên dòng chữ xuống hàng khác đi, cả đoạn bị xô. Font tiếng Việt còn có thêm cái khó: tệp font đủ dấu tiếng Việt lớn hơn tệp chỉ có chữ Latin cơ bản.
- Chỉ tải các độ đậm thật sự dùng (thường 400 và 700), đừng tải cả chín độ đậm.
- Dùng phạm vi ký tự
vietnamesevàlatincủa Google Fonts, bỏcyrillic,greek. <link rel="preload" as="font" crossorigin>cho tệp font chính dùng ở nội dung đầu trang.- Khai font dự phòng có số đo gần giống bằng
size-adjusttrong@font-face, để lúc đổi font không làm dòng nhảy. - Cân nhắc dùng font hệ thống cho thân bài: nhanh nhất, không xô lệch, hiển thị tiếng Việt tốt trên mọi điện thoại hiện nay.
Trang sản phẩm và danh mục: những chỗ nhảy riêng của shop online
Shop online có vài nguồn xô lệch mà site nội dung không có:
- Giá và tình trạng hàng tải sau bằng một lượt gọi riêng để luôn mới. Khung giá trống rồi bỗng có giá cùng nhãn “Giảm 30%” làm khối nút mua dịch xuống. Dựng sẵn giá từ máy chủ; nếu phải cập nhật thì thay chữ trong khung có kích thước cố định.
- Bộ chọn biến thể (màu, cỡ) hiện sau khi kịch bản chạy, đẩy nút “Thêm vào giỏ” xuống đúng lúc người dùng định bấm. Đây là xô lệch đắt nhất vì nó dẫn tới bấm nhầm.
- Thanh trượt ảnh sản phẩm hiện ảnh đầu ở cỡ tự nhiên rồi mới thu về khung khi thư viện khởi tạo xong. Đặt khung tỉ lệ cố định cho vùng ảnh ngay trong CSS.
- Nhãn “Đã bán 1,2k”, sao đánh giá chèn dưới tên sản phẩm trong lưới danh mục sau khi tải: mỗi thẻ sản phẩm cao thêm một dòng, cả lưới xô.
- Thanh “Mua kèm giảm giá”, “Khách vừa đặt hàng” bật lên ở góc màn hình: đặt nổi, không chèn vào bố cục.
Nguyên tắc chung của trang bán hàng: khối nút mua không được phép dịch chuyển sau khi đã hiện. Kiểm riêng điều này bằng cách tải trang sản phẩm trên điện thoại với mạng chậm và nhìn nút mua trong ba giây đầu.
Đo và tìm phần tử gây xô lệch
- Search Console, Chỉ số thiết yếu về trang web: xem nhóm trang nào có CLS kém.
- PageSpeed Insights cho địa chỉ ví dụ: phần chẩn đoán “Tránh những thay đổi lớn về bố cục” liệt kê phần tử bị dời và điểm của từng cái.
- Chrome, công cụ nhà phát triển, tab Performance: bật mục Layout Shifts, ghi lại lúc tải trang và cuộn xuống. Mỗi lần xô lệch hiện thành ô màu, bấm vào thấy phần tử nào.
- Thử trên điện thoại thật với mạng chậm: một số xô lệch chỉ xảy ra khi tài nguyên về chậm.
- Chạy chấm điểm SEO để loại trừ nguyên nhân ở máy chủ: HTML nặng bất thường và phản hồi chậm làm trang hiện từng mảng, dễ sinh xô lệch.
Lưu ý: số thử nghiệm của Lighthouse chỉ đo lúc tải trang; xô lệch xảy ra khi cuộn xuống (quảng cáo tải chậm ở giữa bài) chỉ thấy trong dữ liệu thực địa. Đừng ngạc nhiên khi Lighthouse báo CLS 0 mà Search Console vẫn báo kém.
Checklist CLS
- Mọi ảnh, video, iframe có width, height hoặc aspect-ratio.
- Vị trí quảng cáo có min-height cố định.
- Banner thông báo, cookie, tải ứng dụng: dựng sẵn hoặc nổi, không chèn đẩy trang.
- Font: ít độ đậm, đúng phạm vi ký tự, tải trước font chính, font dự phòng cùng số đo.
- Khối tải bằng JavaScript có khung giữ chỗ cùng kích thước.
- Hiệu ứng dùng transform, không dùng top, margin, height.
- Kiểm cả lúc cuộn, không chỉ lúc tải.
Hỏi đáp
CLS bao nhiêu là tốt?
Dưới 0,1 ở phân vị thứ 75 của lượt truy cập thật là tốt. Từ 0,1 đến 0,25 cần cải thiện, trên 0,25 là kém.
Bấm nút Xem thêm làm nội dung mở ra có bị tính CLS không?
Không, nếu nội dung thay đổi trong vòng 500 mili giây sau thao tác của người dùng. CLS chỉ tính các xô lệch bất ngờ.
Vì sao Lighthouse báo CLS bằng 0 nhưng Search Console vẫn báo kém?
Lighthouse chỉ đo lúc tải trang, không cuộn. Xô lệch do quảng cáo hoặc khối tải chậm khi người dùng cuộn xuống chỉ xuất hiện trong dữ liệu người dùng thật.
Có cần bỏ font web để hết CLS không?
Không bắt buộc. Tải đúng phạm vi ký tự, ít độ đậm, tải trước font chính và khai font dự phòng cùng số đo thường đủ để chữ không nhảy.
Đọc tiếp

Tối ưu ảnh cho tốc độ: WebP, AVIF, srcset và lazy loading đúng chỗ
Ảnh là thứ nặng nhất trên phần lớn trang web Việt, và cũng dễ sửa nhất. Đổi sang WebP hoặc AVIF, phục vụ đúng kích thước theo màn hình, kha…

INP: trang “ì” khi bấm, đo ở đâu và sửa JavaScript nào trước
INP (Interaction to Next Paint) đo khoảng thời gian từ lúc người dùng bấm, chạm hay gõ tới lúc màn hình đổi theo. Dưới 200 mili giây là tốt…

TTFB và Core Web Vitals: con số nào ảnh hưởng thứ hạng, con số nào chỉ để báo cáo
Google dùng ba chỉ số Core Web Vitals đo trên người dùng thật (LCP ≤2,5s, INP ≤200ms, CLS ≤0,1 ở phân vị 75), không dùng điểm Lighthouse. T…

Lập chỉ mục ưu tiên thiết bị di động: bản điện thoại là bản Google đọc
Từ năm 2023 Google thu thập và lập chỉ mục gần như mọi site bằng Googlebot điện thoại. Thứ gì không có trên bản điện thoại thì với Google c…