Categories PageSpeed Insights

Largest Contentful Paint (LCP) là gì?

Largest Contentful Paint (LCP) là một chỉ số quan trọng, đặt người dùng vào trung tâm (user-centric) để đo đạc tốc độ tải nhận thức (perceived load speed), bởi vì nó đánh dấu thời điểm trong timeline* tải trang khi mà nội dung chính (main content) của trang có khả năng đã tải xong- “LCP nhanh” giúp trấn an người dùng rằng trang là hữu ích (vì họ sớm biết nội dung lớn nhất trên trang là gì).

(*): timeline là kiểu chuỗi quá trình diễn ra sự kiện, giống như lịch biểu.

Lưu ý của người dịch: nội dung lớn nhất (largest content) chỉ đến nội dung (phần tử) có kích cỡ chiều cao và chiều rộng lớn nhất, chứ không phải là dung lượng tính theo byte của nó. Một khối văn bản có kích cỡ rộng dài 300px x 500px chỉ có dung lượng tính theo byte chưa đến 1KB sẽ là nội dung lớn nhất, ngay cả khi một bức ảnh 300px x 200px có dung lượng tính theo byte là 10KB. Có vẻ như giả định của Google là phần tử lớn nhất có khả năng cao là phần tử quan trọng nhất, hay ít ra, điều chắc chắn hơn nó là phần tử chiếm không gian lớn nhất trong khung nhìn trình duyệt. OK, giờ chúng ta đi vào phần chính.

Trong lịch sử, đã có những khó khăn, thử thách dành cho các lập trình viên trong nhiệm vụ đo đạc mức độ nhanh chóng của nội dung chính trong khi trang web tải về và hiển thị cho người dùng.

Các chỉ số cũ như load hoặc DOMContentLoaded không tốt vì chúng không nhất thiết đại diện cho cái mà người dùng thấy trên màn hình của họ. Và các chỉ số mới hơn, các chỉ số hiệu suất lấy người dùng làm trung tâm, chẳng hạn như First Contentful Paint (FCP) chỉ nắm bắt được duy nhất thời điểm bắt đầu trong trải nghiệm tải trang (loading experience) mà thôi. Nếu một trang hiển thị trên màn hình bị giật (splash) hoặc chỉ hiển thị chỉ báo tải (loading indicator), khoảnh khắc đó chẳng liên quan gì đến người dùng cả.

Trong quá khứ, chúng tôi khuyến khích dùng các chỉ số hiệu suất như First Meaningful Paint (FMP) và Speed Index (SI / chỉ số tốc độ)- cả hai hiện đều có trong Lighthouse để giúp bạn nắm bắt được nhiều hơn chuyện gì đang diễn ra trong trải nghiệm của người dùng sau khi FCP có mặt. Tuy nhiên các chỉ số này lại phức tạp, khó giải thích, và thường bị hiểu sai-ý-nghĩa (wrong-meaning). Chúng vẫn không chỉ ra được khi nào nội dung chính của trang được tải xong.

Đôi khi, đơn giản hơn sẽ tốt hơn. Dựa trên các thảo luận trong nhóm W3C Web Performance Working và nghiên cứu được tiến hành bởi chính Google, chúng tôi phát hiện ra cách thức chính xác hơn để đo đạc khi nào nội dung chính của trang đã được tải là nhìn vào thời điểm khi phần tử lớn nhất được kết xuất (render).

Chú thích của người dịch: Như vậy là có mối tương quan khá chắc chắn giữa nội dung chính và nội dung lớn nhất. Và xác định nội dung chính không dễ dàng gì (nó liên quan đến ý nghĩa, cái mà máy móc vốn không mạnh hoặc có thể rất tốn kém để phân tích được), do vậy các nhà lập trình dựa vào hình bóng dễ tính toán hơn- đó là kích cỡ của nội dung.


#1. LCP là gì?

Chỉ số Largest Contentful Paint (LCP) báo cáo thời gian kết xuất của phần tử nội dung có kích cỡ lớn nhất (largest content element) hiển thị trong viewport (khung nhìn trình duyệt).

Giá trị của LCP là bao nhiêu thì được xem là tốt?

Để có được trải nghiệm người dùng tốt, các trang web phải phấn đấu để có được Largest Contentful Paint xuất hiện trong 2,5 giây đầu tiên khi trang bắt đầu tải. Để đảm bảo bạn đạt được mục tiêu này cho hầu hết người dùng, ngưỡng tốt để đo là phân vị thứ 75 khi trang tải, phân khúc qua thiết bị di động và máy tính để bàn.

Các phần tử nào được xem xét?

Theo chỉ định hiện tại trong Largest Contentful Paint API, các kiểu phần tử sau được xem xét trong Largest Contentful Paint:

  • Các phần tử <img>
  • Các phần từ <image> nằm bên trong phần tử <svg>
  • Các phần tử <video> (ảnh poster được sử dụng)
  • Một phần tử với ảnh background được tải thông qua hàm url(), trái ngược với CSS gradient
  • Các phần tử cấp khối chứa các nút văn bản hoặc các phần tử con văn bản cấp nội tuyến khác.

Lưu ý, việc giới hạn các phần tử trong bộ giới hạn này là có chủ ý để giữ cho mọi thứ đơn giản ngay từ đầu. Các phần tử bổ sung (ví dụ <svg>, <video>) có thể được thêm vào trong tương lai khi nhiều nghiên cứu hơn được tiến hành.

Làm thế nào phát hiện ra phần tử có kích cỡ lớn nhất?

Kích cỡ của phần tử được báo cáo cho Largest Contentful Paint thường là kích cỡ hiển thị cho người dùng trong viewport (khung nhìn trình duyệt). Nếu phần tử mở rộng ra bên ngoài viewport, hoặc nếu bất kỳ phần tử nào bị cắt hoặc bị tràn ra không nhìn thấy được, những phần dôi ra đó không được tính vào kích thước thành phần.

Với các phần tử ảnh được resize (thay đổi kích cỡ) từ intrinsic size của chúng, kích thước được báo cáo sẽ có thể là kích thước hiển thị hoặc kích thước intrinsic (nội tại), cái được lấy là cái nhỏ hơn. Lấy ví dụ, các ảnh được thu nhỏ lại thành nhỏ hơn nhiều so với kích cỡ intrinsic sẽ chỉ bảo cáo kích cỡ chúng hiển thị, trong khi đó, hình ảnh được kéo dài ra hoặc mở rộng lớn hơn sẽ chỉ báo cáo kích thước intrinsic của chúng.

Với các phần tử văn bản, chỉ kích cỡ của các điểm nút văn bản là được xem xét (hình chữ nhật nhỏ nhất bao gồm tất cả các nút văn bản).

Với tất cả các phần tử, bất cứ margin (lề ngoài), padding (lề trong), hoặc border (đường viền) nào được áp dụng thông qua CSS cũng không được tính thêm vào.

Lưu ý: Việc xác định các nút văn bản nào thuộc về phần tử nào đôi khi có thể khó khăn, đặc biệt với các phần tử mà nó là phần tử cha của các phần tử nội tuyến và các nút văn bản thuần túy nhưng cũng là các phần tử cấp độ khối (block-level). Điểm trọng tâm ở đây là mọi nút văn bản thuộc về (và chỉ thuộc về) phần tử tổ tiên cấp khối gần nhất của nó. Dưới khía cạnh spec: từng nút văn bản thuộc về phần từ mà tạo ra các khối chứa của nó.

Khi nào thì largest contentful paint được báo cáo?

Các trang web thường tải theo giai đoạn, và hệ quả có thể xảy ra tình trạng phần tử lớn nhất trên trang có thể thay đổi.

Để xử lý khả năng thay đổi này, trình duyệt gửi đi PerformanceEntry của kiểu largest-contentful-paint xác định phần tử largest contentful sớm nhất có thể khi trình duyệt kết xuất frame (khung) đầu tiên. Nhưng sau đó, sau khi frame tiếp theo được render, nó sẽ gửi một PerformanceEntry khác bất cứ khi nào phần tử có nội dung lớn nhất thay đổi.

Điều quan trọng cần lưu ý là một phần tử chỉ có thể được xem là phần tử nội dung lớn nhất một khi nó đã được kết xuất và hiển thị cho người dùng. Các ảnh mà hiện vẫn chưa được tải không được coi là “đã kết xuất/rendered”. Ngay cả các nút văn bản sử dụng web font trong giai đoạn chặn font. Trong trường hợp như vậy, một phần tử nhỏ hơn có thể được báo cáo là phần tử nội dung có kích cỡ lớn nhất, nhưng ngay khi phần tử lớn hơn hoàn thành kết xuất, nó sẽ được báo cáo thông qua đối tượng PerformanceEntry khác.

Ngoài hình ảnh và font chữ tải muộn, trang có thể bổ sung các phần tử mới vào DOM khi nội dung mới có sẵn. Nếu bất kỳ phần tử mới nào lớn hơn phần tử lớn nhất trước đó, một PerformanceEntry mới cũng sẽ được báo cáo.

Nếu trang loại bỏ một phần tử khỏi DOM, phần tử đó sẽ không còn được xem xét, đánh giá nữa. Tương tự, nếu một tài nguyên hình ảnh liên quan của một phần tử thay đổi (ví dụ thay đổi img.src thông qua JavaScript), sau đó phần tử này sẽ bị dừng đánh giá cho đến khi ảnh mới được tải.

Trình duyệt sẽ ngừng báo cáo mục mới ngay khi người dùng tương tác với trang (thông qua bấm chạm, cuộn chuột, hoặc nhấn phím), vì sự tương tác của người dùng thường thay đổi những gì được hiển thị cho chính họ (điều này đặc biệt chính xác với việc cuộn chuột / scrolling).

Với mục tiêu phân tích, bạn chỉ nên báo cáo PerformanceEntry được gửi gần đây nhất cho dịch vụ phân tích của mình.

Chú ý: Vì người dùng có thể mở trang trong tab background, có khả năng là largest contentful paint sẽ không xảy ra cho đến khi người dùng tập trung vào tab, cái có thể muộn hơn nhiều so với khi họ lần đầu tiên tải nó.

Thời gian load vs. thời gian render

Vì các lý do bảo mật, timestamp kết xuất của ảnh không hiển thị cho các ảnh có nguồn gốc chéo (cross-origin) mà thiếu tiêu đề Timing-Allow-Origin. Thay vì thế, chỉ thời gian tải của nó được trình diện (vì điều này đã được trình diện qua nhiều API web khác).

Ví dụ sử dụng bên dưới cho thấy cách xử lý các phần tử mà thời gian kết xuất không có sẵn. Nhưng, khi có thể, chúng tôi luôn khuyến khích đặt tiêu đề Timing-Allow-Origin, vì thế các chỉ số của bạn sẽ chính xác hơn.

Phần tử thay đổi layout và kích cỡ được xử lý như thế nào?

Để tránh vấn đề hiệu suất do quá tải tính toán và giữ các chỉ số hiệu suất mới tiêu tốn ở mức thấp, việc thay đổi kích cỡ phần tử hoặc vị trí không tạo thành ứng cứ viên LCP mới. Chỉ các kích cỡ và vị trí ban đầu của phần tử trong khung nhìn trình duyệt là được xem xét.

Điều này có nghĩa là các ảnh ban đầu được hiển thị ngoài màn hình (off-screen) rồi sau đó chuyển thành trong màn hình (on-screen) có thể không được báo cáo ghi nhận. Điều này cũng có nghĩa là các phần tử ban đầu được render trong khung nhìn trình duyệt rồi sau đó được ấn xuống bên dưới, đi ra bên ngoài sẽ vẫn được báo cáo như lúc đầu, như là khi nó chưa bị ấn xuống bên dưới.

Tuy nhiên, (như đề cập ở trên) một phần tử sẽ bị loại khỏi quá trình đánh giá nếu nó đã bị loại khỏi DOM hoặc nếu tài nguyên hình ảnh liên quan đến nó thay đổi.

Các ví dụ

Dưới đây là một số ví dụ khi Largest Contentful Paint xuất hiện trên một số website phổ biến (phần tử lớn nhất được đánh dấu bằng hình chữ nhật với các nét đứt màu xanh):

FCP đến LCP
FCP đến LCP, trang khác

Trong cả hai timeline phía trên, phần tử lớn nhất thay đổi khi nội dung tải. Trong ví dụ đầu tiên, nội dung mới được thêm vào DOM và điều này làm thay đổi phần tử lớn nhất. Trong ví dụ thứ hai, layout thay đổi và nội dung lớn nhất trước đó bị loại bỏ khỏi khung nhìn trình duyệt.

Trong khi đó là điều thường xảy ra khi mà nội dung tải muộn hơn thường sẽ lớn hơn nội dung đã có sẵn trên trang, nó không nhất thiết đúng trong mọi trường hợp. Hai ví dụ tiếp theo cho thấy Largest Contentful Paint xuất hiện trước khi trang được tải đầy đủ.

LCP của Instagram
LCP của Google

Trong ví dụ đầu tiên, logo của Instagram được tải tương đối sớm và nó vẫn là phần tử lớn nhất sau này, dù các nội dung khác dần dần hiển thị. Trong ví dụ về các kết quả tìm kiếm của Google, phần tử lớn nhất là đoạn văn bản được hiển thị trước bất kỳ ảnh hoặc logo nào. Vì các ảnh cụ thể vẫn nhỏ hơn so với văn bản này, nó vẫn là phần tử lớn nhất trong suốt quá trình tải.

Lưu ý: Trong frame đầu tiên của timeline Instagram, bạn có thể để ý đến logo camera không có hộp màu xanh bao quanh nó. Đó là vì nó là phần tử <svg>, và các phần tử <svg> hiện vẫn chưa được coi là ứng cử viên trong LCP. Đối tượng được xem là LCP đầu tiên là văn bản trong frame thứ hai.


#2. Làm thế nào để đo được LCP

LCP có thể được đo trong điều kiện thử nghiệm (lab) hoặc trong điều kiện tự nhiên (field), và nó có sẵn trong các công cụ sau:

Các công cụ tự nhiên:

  • Báo cáo trải nghiệm người dùng của Chrome
  • PageSpeed Insights
  • Search Console (báo cáo Core Web Vitals)

Các công cụ thử nghiệm:

Đo đạc LCP trong JavaScript

Bạn có thể đo đạc LCP trong JavaScript sử dụng API Largest Contentful Paint. Ví dụ dưới đây cho thấy cách tạo ra PerformanceObserver dùng để lắng nghe các mục nhập largest-contentful-paint và ghi lại giá trị LCP vào console:

// Create a variable to hold the latest LCP value (since it can change).
let lcp;
// Create the PerformanceObserver instance.
const po = new PerformanceObserver((entryList) => {
  const entries = entryList.getEntries();
  const lastEntry = entries[entries.length - 1];
  // Update `lcp` to the latest value, using `renderTime` if it's available,
  // otherwise using `loadTime`. (Note: `renderTime` may not be available if
  // the element is an image and it's loaded cross-origin without the
  // `Timing-Allow-Origin` header.)
  lcp = lastEntry.renderTime || lastEntry.loadTime;
});
// Observe entries of type `largest-contentful-paint`, including buffered
// entries, i.e. entries that occurred before calling `observe()`.
po.observe({type: 'largest-contentful-paint', buffered: true});
// Send the latest LCP value to your analytics server once the user
// leaves the tab.
addEventListener('visibilitychange', function fn() {
  if (lcp && document.visibilityState === 'hidden') {
    console.log('LCP:', lcp);
    removeEventListener('visibilitychange', fn, true);
  }
}, true);

Lưu ý, ví dụ này đợi để log LCP cho đến khi trạng thái vòng đời của trang (lifecycle state) thay đổi thành ẩn. Điều này là cách để đảm bảo rằng nó chỉ log entry cuối cùng.

Sẽ thế nào nếu phần tử lớn nhất không phải quan trọng nhất?

Trong một số trường hợp (các) phần tử quan trọng nhất trên trang lại không phải là phần tử lớn nhất, và người lập trình có thể quan tâm hơn đến việc đo đạc thời gian kết xuất của những phần tử thay thế này. Điều đó có thể làm được thông qua việc sử dụng API Element Timing, cũng đã được mô tả trong bài viết các chỉ số tùy chỉnh (custom metrics).


#3. Làm thế nào cải thiện được LCP

LCP chậm chủ yếu bị ảnh hưởng bởi các yếu tố sau:

  • Thời gian phản hồi của máy chủ chậm
  • CSS và JavaScript chặn hiển thị
  • Thời gian tải tài nguyên
  • Kết xuất phía máy khách

Cũng vậy, nếu trang của bạn được render trên máy khách, và phần tử nội dung có kích cỡ lớn nhất được thêm vào DOM thông qua JavaScript, sau đó script của bạn được phân tích, biên dịch, và thời gian thực thi cũng có thể là một yếu tố trong LCP.

Có một số thông tin bạn cần tìm hiểu thêm để tối ưu hóa tất cả các yếu tố này:

Chuỗi bài viết về các chỉ số tăng tốc:

(Dịch từ bài viết Largest Contentful Paint, tác giả: Philip Walton, từ trang web dev)

Comments are closed.

Back to Top