Tối ưu hoá thời gian hiển thị nội dung lớn nhất

Hướng dẫn từng bước về cách phân tích LCP và xác định những khía cạnh chính cần cải thiện.

Thời gian hiển thị nội dung lớn nhất (LCP) là một trong 3 chỉ số Chỉ số quan trọng chính của trang web và cho biết tốc độ tải nội dung chính của một trang web. Cụ thể, LCP đo lường thời gian từ khi người dùng bắt đầu tải trang cho đến khi hình ảnh hoặc khối văn bản lớn nhất được hiển thị trong khung nhìn.

Để cung cấp trải nghiệm tốt cho người dùng, các trang web nên đặt mục tiêu đạt LCP là 2,5 giây trở xuống cho ít nhất 75% lượt truy cập trang.

Giá trị LCP tốt là từ 2,5 giây trở xuống, giá trị kém lớn hơn 4,0 giây và bất kỳ mức độ nào còn lại cần cải thiện
Giá trị LCP tốt là từ 2,5 giây trở xuống.

Một số yếu tố có thể ảnh hưởng đến tốc độ tải và hiển thị của trình duyệt đối với một trang web cũng như sự chậm trễ của bất kỳ yếu tố nào trong số đó cũng có thể ảnh hưởng đáng kể đến LCP.

Hiếm khi việc sửa nhanh một phần của trang lại có thể mang lại sự cải thiện có ý nghĩa cho LCP. Để cải thiện LCP, bạn phải xem xét toàn bộ quá trình tải và đảm bảo mọi bước trong quá trình này đều được tối ưu hoá.

Tìm hiểu về chỉ số LCP

Trước khi tối ưu hoá LCP, nhà phát triển nên tìm hiểu xem họ có gặp vấn đề về LCP hay không và mức độ của vấn đề đó.

Có thể đo LCP bằng một số công cụ và không phải tất cả các công cụ này đo LCP theo cùng một cách. Để hiểu LCP của người dùng thực tế, chúng ta nên xem xét những gì người dùng thực tế đang trải nghiệm, thay vì những gì một công cụ trong phòng thí nghiệm như Lighthouse hoặc thử nghiệm cục bộ cho thấy. Những công cụ tại phòng thí nghiệm này có thể cung cấp rất nhiều thông tin để giải thích và giúp bạn cải thiện LCP, nhưng hãy lưu ý rằng nếu chỉ thử nghiệm trong phòng thí nghiệm thì có thể không hoàn toàn đại diện được cho những gì người dùng thực tế của bạn trải nghiệm.

Dữ liệu LCP dựa trên người dùng thực tế có thể hiển thị qua các công cụ Giám sát người dùng thực (rum) được cài đặt trên một trang web hoặc bằng cách sử dụng Báo cáo trải nghiệm người dùng trên Chrome (CrUX). Báo cáo này thu thập dữ liệu ẩn danh từ người dùng Chrome thực cho hàng triệu trang web.

Sử dụng dữ liệu LCP CrUX của PageSpeed Insights

PageSpeed Insights cung cấp quyền truy cập vào dữ liệu CrUX ở phần trên cùng có nhãn Khám phá những gì người dùng thực của bạn đang trải nghiệm. Bạn có thể xem dữ liệu chi tiết hơn về phòng thí nghiệm trong phần dưới cùng có nhãn Chẩn đoán các vấn đề về hiệu suất. Nếu dữ liệu CrUX có sẵn cho trang web của bạn, hãy luôn tập trung vào dữ liệu người dùng thực trước tiên.

Dữ liệu CrUX có trong PageSpeed Insights
Dữ liệu CrUX xuất hiện trong PageSpeed Insights.

PageSpeed Insights hiển thị tối đa 4 dữ liệu CrUX khác nhau:

  • Dữ liệu thiết bị di động cho URL này
  • Dữ liệu trên máy tính cho URL này
  • Dữ liệu thiết bị di động cho toàn bộ Nguồn gốc
  • Dữ liệu trên máy tính cho toàn bộ Nguồn gốc

Bạn có thể bật/tắt các lựa chọn này trong các nút điều khiển ở trên cùng và phía trên bên phải của phần này. Nếu một URL không có đủ dữ liệu để hiển thị ở cấp URL nhưng có dữ liệu cho nguồn gốc, thì PageSpeed Insights sẽ luôn hiển thị dữ liệu gốc.

PageSpeed Insights trở lại dữ liệu cấp nguồn gốc khi không có dữ liệu cấp url
Khi không có dữ liệu ở cấp URL, PageSpeed Insights sẽ hiển thị dữ liệu cấp nguồn gốc.

LCP cho toàn bộ nguồn gốc có thể rất khác với LCP của một trang riêng lẻ, tuỳ thuộc vào cách LCP được tải trên trang đó so với các trang khác trên nguồn gốc đó. Số liệu cũng có thể bị ảnh hưởng bởi cách khách truy cập điều hướng đến các trang này. Trang chủ thường được người dùng mới truy cập, vì vậy, các trang này thường có thể được tải "lạnh", mà không có bất kỳ nội dung nào được lưu vào bộ nhớ đệm và do đó, thường là các trang chậm nhất trên trang web.

Việc xem xét 4 danh mục dữ liệu CrUX có thể giúp bạn biết được liệu một vấn đề về LCP chỉ xảy ra trên trang này hay là vấn đề chung trên toàn trang web. Tương tự, báo cáo này có thể cho biết loại thiết bị nào có vấn đề về LCP.

Sử dụng các chỉ số bổ sung CrUX của PageSpeed Insights

Những người muốn tối ưu hoá LCP cũng nên sử dụng thời gian Thời gian hiển thị nội dung đầu tiên (FCP)Thời gian cho byte đầu tiên (TTFB). Đây là những chỉ số chẩn đoán hiệu quả có thể cung cấp thông tin chi tiết có giá trị về LCP.

TTFB là thời gian khi khách truy cập bắt đầu điều hướng đến một trang (ví dụ: nhấp vào một đường liên kết), cho đến khi nhận được các byte đầu tiên của tài liệu HTML. Chỉ số TTFB cao có thể khiến việc đạt được LCP 2,5 giây trở nên khó khăn, hoặc thậm chí là không thể.

TTFB cao có thể là do nhiều lần chuyển hướng máy chủ, khách truy cập ở xa máy chủ của trang web gần nhất, khách truy cập có điều kiện mạng kém hoặc không thể sử dụng nội dung được lưu vào bộ nhớ đệm do tham số truy vấn.

Khi một trang bắt đầu hiển thị, có thể có hiển thị ban đầu (ví dụ: màu nền), sau đó là một số nội dung xuất hiện (ví dụ: tiêu đề trang web). Giao diện của nội dung ban đầu được đo bằng FCP. delta giữa FCP và các chỉ số khác có thể rất dễ hiểu.

Một delta lớn giữa TTFB và FCP có thể cho thấy trình duyệt cần tải xuống nhiều nội dung chặn hiển thị. Đó cũng có thể là một dấu hiệu cho thấy rằng phải hoàn thành rất nhiều việc để hiển thị nội dung có ý nghĩa – dấu hiệu điển hình của một trang web phụ thuộc nhiều vào chế độ hiển thị phía máy khách.

Một delta lớn giữa FCP và LCP cho biết tài nguyên LCP không có sẵn ngay để trình duyệt ưu tiên (ví dụ: văn bản hoặc hình ảnh được quản lý bằng JavaScript thay vì có sẵn trong HTML ban đầu) hoặc trình duyệt đang hoàn tất công việc khác trước khi có thể hiển thị nội dung LCP.

Sử dụng dữ liệu PageSpeed Insights Lighthouse

Mục Lighthouse của PageSpeed Insights cung cấp một số hướng dẫn để cải thiện LCP, nhưng trước tiên bạn nên kiểm tra xem LCP được cung cấp có nhất quán với dữ liệu người dùng thực do CrUX cung cấp hay không. Nếu Lighthouse và CrUX không thống nhất, thì CrUX có thể cung cấp thông tin chính xác hơn về trải nghiệm người dùng của bạn. Hãy đảm bảo rằng dữ liệu CrUX là dữ liệu về trang của bạn, chứ không phải nguồn gốc đầy đủ trước khi bạn hành động dựa trên dữ liệu đó.

Nếu cả Lighthouse và CrUX đều hiển thị các giá trị LCP cần cải thiện, thì mục Lighthouse có thể cung cấp hướng dẫn hữu ích về cách cải thiện LCP. Sử dụng bộ lọc LCP để chỉ hiển thị các lượt kiểm tra liên quan đến LCP như sau:

Cơ hội và thông tin chẩn đoán về LCP của Lighthouse
Thông tin chẩn đoán và đề xuất về ngọn hải đăng để cải thiện LCP.

Bên cạnh Cơ hội cần cải thiện, phần Chẩn đoán có thể cung cấp thêm thông tin giúp chẩn đoán vấn đề. Chẩn đoán phần tử Thời gian hiển thị nội dung lớn nhất hiển thị thông tin chi tiết hữu ích về các dấu thời gian khác nhau tạo nên LCP:

Các giai đoạn LCP của Lighthouse
Bảng chi tiết của Lighthouse về các thành phần LCP.

Chúng ta sẽ tìm hiểu kỹ hơn về các phần phụ này trong phần tiếp theo.

Bảng chi tiết LCP

Tối ưu hoá LCP có thể là một tác vụ phức tạp hơn khi PageSpeed Insights không cung cấp cho bạn câu trả lời về cách cải thiện chỉ số này. Đối với các công việc phức tạp, thông thường, bạn nên chia chúng thành các công việc nhỏ hơn, dễ quản lý hơn và giải quyết riêng từng công việc.

Phần này trình bày phương pháp chia nhỏ LCP thành các phần quan trọng nhất, sau đó trình bày các đề xuất cụ thể và phương pháp hay nhất để tối ưu hoá từng phần.

Hầu hết lượt tải trang thường bao gồm một số yêu cầu mạng, nhưng để xác định cơ hội cải thiện LCP, bạn chỉ nên bắt đầu bằng cách xem xét hai:

  1. Tài liệu HTML ban đầu
  2. Tài nguyên LCP (nếu có)

Mặc dù các yêu cầu khác trên trang có thể ảnh hưởng đến LCP, nhưng hai yêu cầu này (cụ thể là các thời điểm tài nguyên LCP bắt đầu và kết thúc) sẽ cho biết liệu trang của bạn có được tối ưu hoá cho LCP hay không.

Để xác định tài nguyên LCP, bạn có thể sử dụng các công cụ cho nhà phát triển (như PageSpeed Insights đã thảo luận ở trên, Công cụ của Chrome cho nhà phát triển hoặc WebPageTest) để xác định phần tử LCP. Từ đó, bạn có thể so khớp URL (xin nhắc lại, nếu có) do phần tử tải trên thác mạng của tất cả tài nguyên được tải trên trang.

Ví dụ: hình ảnh sau đây cho thấy những tài nguyên này được làm nổi bật trên biểu đồ thác nước mạng từ một lượt tải trang thông thường, trong đó phần tử LCP đòi hỏi phải có một yêu cầu hình ảnh để hiển thị.

Thác nước trên mạng, trong đó các tài nguyên HTML và LCP được làm nổi bật
Biểu đồ thác nước cho thấy thời gian tải cho HTML của trang web và những tài nguyên mà LCP cần.

Đối với một trang được tối ưu hoá đúng cách, bạn muốn yêu cầu tài nguyên LCP bắt đầu tải sớm nhất có thể, đồng thời bạn muốn phần tử LCP hiển thị nhanh nhất có thể sau khi tài nguyên LCP tải xong. Để giúp hình dung liệu một trang cụ thể có đang tuân theo nguyên tắc này hay không, bạn có thể chia nhỏ tổng thời gian LCP thành các phần phụ sau:

Thời gian cho byte đầu tiên (TTFB)
Khoảng thời gian từ khi người dùng bắt đầu tải trang cho đến khi trình duyệt nhận được byte đầu tiên của phản hồi tài liệu HTML.
Độ trễ khi tải tài nguyên
Khoảng thời gian tính từ thời điểm TTFB đến khi trình duyệt bắt đầu tải tài nguyên LCP. Nếu phần tử LCP không yêu cầu tải tài nguyên để hiển thị (ví dụ: nếu phần tử là một nút văn bản được hiển thị bằng phông chữ hệ thống), thì thời gian này là 0.
Thời gian tải tài nguyên
Khoảng thời gian cần thiết để tải chính tài nguyên LCP. Nếu phần tử LCP không yêu cầu tải tài nguyên để hiển thị, thì thời gian này là 0.
Độ trễ khi kết xuất phần tử
Khoảng thời gian tính từ khi tài nguyên LCP tải xong đến khi phần tử LCP hiển thị đầy đủ.

LCP của mỗi trang bao gồm bốn danh mục con sau. Không có khoảng cách hay sự chồng chéo giữa các mô-đun này và chúng cộng lại theo thời gian LCP đầy đủ.

Bảng chi tiết về LCP cho thấy 4 danh mục phụ
Cùng một sơ đồ thác nước, với 4 danh mục con LCP được phủ lên tiến trình.

Mỗi trang đều có thể chia giá trị LCP thành bốn phần phụ sau. Không có sự chồng chéo hoặc khoảng cách giữa các quảng cáo. Các con số này cộng lại với thời gian LCP đầy đủ.

Khi tối ưu hoá LCP, bạn nên cố gắng tối ưu hoá từng phần phụ. Nhưng một điều quan trọng cũng cần nhớ là bạn cần tối ưu hoá tất cả các chiến dịch đó. Trong một số trường hợp, việc tối ưu hoá áp dụng cho một phần sẽ không cải thiện LCP mà chỉ chuyển thời gian lưu cho phần khác.

Ví dụ: trong thác nước mạng trước đó, nếu bạn giảm kích thước tệp của hình ảnh bằng cách nén nhiều hơn hoặc chuyển sang một định dạng tối ưu hơn (chẳng hạn như AVIF hoặc WebP), thì điều đó sẽ giảm thời lượng tải tài nguyên, nhưng thực ra sẽ không cải thiện LCP vì thời gian sẽ chỉ chuyển sang phần phụ độ trễ hiển thị phần tử:

Phân tích LCP tương tự được trình bày trước đó, trong đó danh mục con thời lượng tải tài nguyên được rút ngắn, nhưng thời gian LCP tổng thể vẫn giữ nguyên.
Việc rút ngắn thời lượng tải tài nguyên sẽ làm tăng độ trễ hiển thị phần tử mà không làm giảm LCP.

Lý do điều này xảy ra là vì trên trang này, phần tử LCP bị ẩn cho đến khi mã JavaScript tải xong và sau đó mọi thứ được tiết lộ cùng một lúc.

Ví dụ này minh hoạ điểm bạn cần tối ưu hoá tất cả các phần phụ này để đạt được kết quả LCP tốt nhất.

Thời gian tối ưu cho các phần phụ

Để tối ưu hoá từng phần phụ của LCP, bạn cần hiểu rõ thông tin lý tưởng trong các phần phụ này trên một trang được tối ưu hoá hợp lý.

Trong 4 phần phụ, 2 phần có tên từ "trì hoãn". Đó là một gợi ý cho biết bạn muốn hiển thị những thời điểm này càng gần 0 càng tốt. Hai phần còn lại liên quan đến các yêu cầu mạng và bản chất của các yêu cầu này cần thời gian.

Phần phụ LCP % LCP (Nội dung lớn nhất hiển thị)
Thời gian đến byte đầu tiên Khoảng 40%
Độ trễ khi tải tài nguyên <10%
Thời gian tải tài nguyên Khoảng 40%
Độ trễ khi kết xuất phần tử <10%
TỔNG CỘNG 100%

Xin lưu ý rằng bảng chi tiết về thời gian này mang tính nguyên tắc chứ không phải là những quy tắc nghiêm ngặt. Nếu thời gian LCP trên các trang của bạn liên tục trong vòng 2,5 giây, thì tỷ lệ tương đối là gì không thực sự quan trọng. Nhưng nếu bạn dành nhiều thời gian không cần thiết cho một trong các phần "độ trễ", thì sẽ rất khó để liên tục đạt được mục tiêu 2,5 giây.

Bạn nên xem xét thông tin chi tiết về thời gian LCP dưới đây:

  • Bạn nên dành phần lớn thời gian LCP để tải tài liệu HTML và nguồn LCP.
  • Bất kỳ lúc nào trước LCP mà một trong hai tài nguyên này không tải đều là cơ hội để cải thiện.

Cách tối ưu hoá từng phần

Giờ đây, khi bạn đã hiểu thời gian của từng phần phụ LCP sẽ được phân tích như thế nào trên một trang được tối ưu hoá hiệu quả, bạn có thể bắt đầu tối ưu hoá các trang của mình.

Bốn phần tiếp theo sẽ trình bày các đề xuất và phương pháp hay nhất về cách tối ưu hoá từng phần. Các giải pháp này được trình bày theo thứ tự, bắt đầu từ những hoạt động tối ưu hoá có khả năng sẽ mang lại tác động lớn nhất.

1. Loại bỏ độ trễ tải tài nguyên

Mục tiêu trong bước này là đảm bảo tài nguyên LCP bắt đầu tải càng sớm càng tốt. Mặc dù trên lý thuyết, tài nguyên sớm nhất có thể bắt đầu tải là ngay sau TTFB, nhưng trong thực tế, luôn có độ trễ trước khi trình duyệt thực sự bắt đầu tải tài nguyên.

Nguyên tắc chung là tài nguyên LCP của bạn nên bắt đầu tải cùng lúc với tài nguyên đầu tiên được trang đó tải. Hay nói cách khác là nếu tài nguyên LCP bắt đầu tải muộn hơn tài nguyên đầu tiên, thì vẫn có cơ hội cải thiện.

Sơ đồ thác nước trên mạng cho thấy tài nguyên LCP bắt đầu sau tài nguyên đầu tiên, cho thấy cơ hội cải thiện
Trên trang này, tài nguyên LCP bắt đầu tải ngay sau khi biểu định kiểu tải đầu tiên. Có những điểm cần cải thiện ở đây.

Nói chung, có hai yếu tố ảnh hưởng đến tốc độ tải của tài nguyên LCP:

  • Khi tìm thấy tài nguyên.
  • Mức độ ưu tiên của tài nguyên.

Tối ưu hoá khi tìm thấy tài nguyên

Để đảm bảo tài nguyên LCP của bạn bắt đầu tải sớm nhất có thể, điều quan trọng là có thể tìm thấy tài nguyên trong phản hồi ban đầu của tài liệu HTML bằng trình quét tải trước của trình duyệt. Ví dụ: trong các trường hợp sau đây, trình duyệt có thể phát hiện tài nguyên LCP bằng cách quét phản hồi của tài liệu HTML:

  • Phần tử LCP là phần tử <img> và các thuộc tính src hoặc srcset của phần tử này có trong mã đánh dấu HTML ban đầu.
  • Phần tử LCP yêu cầu hình nền CSS, nhưng hình ảnh đó được tải trước bằng cách sử dụng <link rel="preload"> trong đánh dấu HTML (hoặc sử dụng tiêu đề Link).
  • Phần tử LCP là một nút văn bản cần phải có phông chữ trên web để hiển thị và phông chữ này được tải bằng <link rel="preload"> trong mã đánh dấu HTML (hoặc sử dụng tiêu đề Link).

Dưới đây là một số ví dụ mà không thể tìm thấy tài nguyên LCP bằng cách quét phản hồi của tài liệu HTML:

  • Phần tử LCP là một <img> được tự động thêm vào trang bằng JavaScript.
  • Phần tử LCP được tải từng phần bằng thư viện JavaScript ẩn các thuộc tính src hoặc srcset (thường là data-src hoặc data-srcset).
  • Phần tử LCP yêu cầu hình nền CSS.

Trong mỗi trường hợp này, trình duyệt cần chạy tập lệnh hoặc áp dụng biểu định kiểu (thường là đợi cho đến khi các yêu cầu mạng kết thúc) rồi mới có thể khám phá tài nguyên LCP và bắt đầu tải. Điều này không bao giờ tối ưu.

Để loại bỏ độ trễ tải tài nguyên không cần thiết, tài nguyên LCP của bạn phải có thể tìm thấy được từ nguồn HTML. Trong trường hợp tài nguyên chỉ được tham chiếu từ một tệp CSS hoặc JavaScript bên ngoài, thì tài nguyên LCP phải được tải trước với mức độ ưu tiên tìm nạp cao, ví dụ:

<!-- Load the stylesheet that will reference the LCP image. -->
<link rel="stylesheet" href="/path/to/styles.css">

<!-- Preload the LCP image with a high fetchpriority so it starts loading with the stylesheet. -->
<link rel="preload" fetchpriority="high" as="image" href="/path/to/hero-image.webp" type="image/webp">

Tối ưu hoá mức độ ưu tiên của tài nguyên

Ngay cả khi có thể tìm thấy tài nguyên LCP từ mã đánh dấu HTML, tài nguyên đó vẫn có thể không bắt đầu tải sớm nhất là tài nguyên đầu tiên. Điều này có thể xảy ra nếu trình duyệt tải trước phỏng đoán ưu tiên của trình quét không nhận ra rằng tài nguyên là quan trọng, hoặc nếu trình duyệt xác định rằng các tài nguyên khác quan trọng hơn.

Ví dụ: bạn có thể trì hoãn hình ảnh LCP của mình bằng HTML nếu đặt loading="lazy" trên phần tử <img>. Khi sử dụng tính năng tải từng phần, tài nguyên sẽ không được tải cho đến khi bố cục xác nhận rằng hình ảnh đang nằm trong khung nhìn, do đó, có thể bắt đầu tải muộn hơn so với thường lệ.

Ngay cả khi không tải từng phần, ban đầu các hình ảnh không được tải ở mức ưu tiên cao nhất bởi các trình duyệt vì chúng không phải là tài nguyên chặn hiển thị. Bạn có thể gợi ý cho trình duyệt biết tài nguyên nào quan trọng nhất bằng cách sử dụng thuộc tính fetchpriority cho những tài nguyên có thể hưởng lợi từ mức độ ưu tiên cao hơn:

<img fetchpriority="high" src="/path/to/hero-image.webp">

Bạn nên đặt fetchpriority="high" trên phần tử <img> nếu cho rằng phần tử đó có thể là phần tử LCP của trang. Tuy nhiên, việc đặt mức độ ưu tiên cao trên nhiều hình ảnh sẽ khiến chế độ cài đặt mức độ ưu tiên không hữu ích trong việc giảm LCP.

Bạn cũng có thể giảm mức độ ưu tiên của những hình ảnh có thể xuất hiện sớm trong nội dung phản hồi của tài liệu nhưng không xuất hiện do cách định kiểu (ví dụ: hình ảnh trong trang trình bày dạng băng chuyền không xuất hiện khi khởi động):

<img fetchpriority="low" src="/path/to/carousel-slide-3.webp">

Giảm mức độ ưu tiên của một số tài nguyên nhất định có thể mang lại nhiều băng thông hơn cho những tài nguyên cần nhiều hơn, nhưng hãy cẩn thận. Luôn kiểm tra mức độ ưu tiên của tài nguyên trong Công cụ cho nhà phát triển và kiểm tra các thay đổi bằng các công cụ tại hiện trường và phòng thí nghiệm.

Sau khi bạn tối ưu hoá mức độ ưu tiên và thời gian khám phá tài nguyên LCP, thác nước mạng của bạn sẽ có dạng như sau (trong đó tài nguyên LCP bắt đầu cùng lúc với tài nguyên đầu tiên):

Sơ đồ thác nước mạng cho thấy tài nguyên LCP hiện đang bắt đầu cùng lúc với tài nguyên đầu tiên
Giờ đây, tài nguyên LCP sẽ bắt đầu tải cùng lúc với biểu định kiểu.

2. Loại bỏ độ trễ hiển thị phần tử

Mục tiêu trong bước này là đảm bảo phần tử LCP có thể hiển thị ngay sau khi tài nguyên tải xong, bất kể thời điểm đó.

Lý do chính khiến phần tử LCP không thể hiển thị ngay sau khi tải xong tài nguyên là nếu quá trình kết xuất bị chặn vì một số lý do khác:

  • Quá trình hiển thị toàn bộ trang sẽ bị chặn do các biểu định kiểu hoặc tập lệnh đồng bộ trong <head> vẫn đang tải.
  • Tài nguyên LCP đã tải xong, nhưng phần tử LCP chưa được thêm vào DOM (đang chờ một số mã JavaScript để tải).
  • Phần tử này đang bị ẩn bởi một số mã khác, chẳng hạn như một thư viện thử nghiệm A/B vẫn đang xác định thử nghiệm mà người dùng nên tham gia.
  • Luồng chính bị chặn do tác vụ dài và tác vụ kết xuất cần phải đợi cho đến khi các tác vụ dài đó hoàn tất.

Các phần sau đây giải thích cách giải quyết các nguyên nhân phổ biến nhất gây ra độ trễ hiển thị phần tử không cần thiết.

Giảm hoặc cùng dòng biểu định kiểu chặn hiển thị

Các biểu định kiểu được tải từ mã đánh dấu HTML sẽ chặn hiển thị tất cả nội dung theo sau chúng. Điều này là tốt vì bạn thường không muốn hiển thị HTML chưa được định kiểu. Tuy nhiên, nếu biểu định kiểu quá lớn đến mức mất nhiều thời gian tải hơn đáng kể so với tài nguyên LCP, thì điều này sẽ ngăn phần tử LCP hiển thị, ngay cả sau khi tài nguyên của nó đã tải xong, như minh hoạ trong ví dụ sau:

Sơ đồ dạng thác nước trên mạng cho thấy một tệp CSS lớn chặn kết xuất phần tử LCP vì phần tử này mất nhiều thời gian tải hơn so với tài nguyên LCP
Hình ảnh và biểu định kiểu bắt đầu tải cùng lúc, nhưng hình ảnh không thể hiển thị cho đến khi biểu định kiểu sẵn sàng.

Để khắc phục vấn đề này, bạn có thể:

  • nội dòng biểu định kiểu vào HTML để tránh yêu cầu mạng bổ sung; hoặc,
  • giảm kích thước của biểu định kiểu.

Nói chung, bạn chỉ nên cùng dòng biểu định kiểu nếu biểu định kiểu của bạn có kích thước nhỏ vì nội dung cùng dòng trong HTML không thể hưởng lợi từ việc lưu vào bộ nhớ đệm trong các lần tải trang tiếp theo. Nếu một biểu định kiểu lớn đến mức mất nhiều thời gian tải hơn so với tài nguyên LCP, thì biểu định kiểu đó khó có thể phù hợp để tải cùng dòng.

Trong hầu hết các trường hợp, cách tốt nhất để đảm bảo biểu định kiểu không chặn quá trình kết xuất phần tử LCP là giảm kích thước để phần tử nhỏ hơn tài nguyên LCP. Việc này sẽ đảm bảo đây không phải là điểm tắc nghẽn trong hầu hết các lượt truy cập.

Một số đề xuất giúp giảm kích thước của biểu định kiểu là:

Hoãn hoặc chặn JavaScript cùng dòng

Bạn hầu như không cần phải thêm tập lệnh đồng bộ (tập lệnh không có thuộc tính async hoặc defer) vào <head> trên các trang của bạn. Việc này hầu như sẽ tác động tiêu cực đến hiệu suất.

Trong trường hợp mã JavaScript cần chạy sớm nhất có thể trong khi tải trang, tốt nhất là bạn nên đặt nội tuyến mã đó để việc hiển thị không bị trì hoãn khi chờ một yêu cầu mạng khác. Tuy nhiên, giống như với biểu định kiểu, bạn chỉ nên đặt tập lệnh nội dòng nếu chúng rất nhỏ.

Không nên
<head>
  <script src="/path/to/main.js"></script>
</head>
Nên
<head>
  <script>
    // Inline script contents directly in the HTML.
    // IMPORTANT: only do this for very small scripts.
  </script>
</head>

Sử dụng tính năng hiển thị phía máy chủ

Hiển thị phía máy chủ (SSR) là quá trình chạy logic ứng dụng phía máy khách của bạn trên máy chủ và phản hồi các yêu cầu tài liệu HTML bằng mã đánh dấu HTML đầy đủ.

Từ góc độ tối ưu hoá LCP, SSR có hai lợi thế chính:

  • Bạn có thể tìm thấy tài nguyên hình ảnh của mình từ nguồn HTML (như đã thảo luận trong bước 1 trước đó).
  • Nội dung trang của bạn sẽ không cần hoàn tất thêm các yêu cầu JavaScript trước khi có thể hiển thị.

Nhược điểm chính của SSR là hệ thống cần thêm thời gian xử lý của máy chủ, nên có thể làm chậm TTFB của bạn. Tuy nhiên, sự đánh đổi này thường đáng giá vì thời gian xử lý của máy chủ nằm trong tầm kiểm soát của bạn, trong khi khả năng của mạng và thiết bị của người dùng thì không.

Tuỳ chọn tương tự như SSR được gọi là tạo trang web tĩnh (SSG) hoặc kết xuất trước. Đây là quá trình tạo trang HTML trong một bước xây dựng chứ không phải quá trình theo yêu cầu. Nếu có thể kết xuất trước với cấu trúc của bạn, thì thường thì đó là lựa chọn tốt hơn về hiệu suất.

Chia nhỏ các tác vụ dài

Ngay cả khi bạn đã làm theo lời khuyên trước đó và mã JavaScript của bạn không chặn hiển thị cũng như không chịu trách nhiệm hiển thị các phần tử của bạn, mã vẫn có thể trì hoãn LCP.

Lý do phổ biến nhất khiến tình trạng này xảy ra là khi các trang tải các tệp JavaScript lớn, cần được phân tích cú pháp và thực thi trên luồng chính của trình duyệt. Điều này có nghĩa là ngay cả khi tài nguyên hình ảnh của bạn đã được tải xuống đầy đủ, tập lệnh đó vẫn có thể phải đợi cho đến khi một tập lệnh không liên quan thực thi xong trước khi có thể kết xuất.

Hiện nay, tất cả trình duyệt đều hiển thị hình ảnh trên luồng chính. Tức là mọi thành phần chặn luồng chính cũng có thể dẫn đến độ trễ hiển thị phần tử không cần thiết.

Giảm thời gian tải tài nguyên

Mục tiêu của bước này là giảm thời gian chuyển các byte tài nguyên qua mạng sang thiết bị của người dùng. Nhìn chung, có 3 cách để làm việc này:

  • Giảm kích thước của tài nguyên.
  • Giảm khoảng cách mà tài nguyên phải di chuyển.
  • Giảm tranh chấp về băng thông mạng.
  • Loại bỏ hoàn toàn thời gian sử dụng mạng.

Giảm kích thước của tài nguyên

Tài nguyên LCP của một trang (nếu có) sẽ là một hình ảnh hoặc một phông chữ web. Các hướng dẫn sau đây sẽ trình bày chi tiết về cách giảm kích thước của cả hai nền tảng:

Giảm khoảng cách mà tài nguyên phải di chuyển

Ngoài việc giảm kích thước tài nguyên, bạn cũng có thể giảm thời gian tải bằng cách đặt máy chủ càng gần người dùng về mặt địa lý càng tốt. Và cách tốt nhất để làm điều đó là sử dụng mạng phân phối nội dung (CDN).

Mạng phân phối nội dung (CDN) hình ảnh đặc biệt hữu ích vì chúng không chỉ giảm khoảng cách tài nguyên phải di chuyển, mà còn thường làm giảm kích thước tài nguyên — tự động triển khai tất cả các đề xuất giảm kích thước đã đưa ra cho bạn.

Giảm tranh chấp về băng thông mạng

Ngay cả khi bạn đã giảm kích thước của tài nguyên cũng như quãng đường mà tài nguyên phải di chuyển, tài nguyên vẫn có thể mất nhiều thời gian để tải nếu bạn tải nhiều tài nguyên khác cùng một lúc. Vấn đề này được gọi là tranh chấp mạng.

Nếu bạn đã cấp cho tài nguyên LCP fetchpriority caobắt đầu tải tài nguyên đó càng sớm càng tốt, thì trình duyệt sẽ cố gắng hết sức để ngăn các tài nguyên có mức độ ưu tiên thấp hơn cạnh tranh với tài nguyên đó. Tuy nhiên, nếu bạn đang tải nhiều tài nguyên có fetchpriority cao hoặc nếu bạn chỉ tải nhiều tài nguyên nói chung, thì điều này có thể ảnh hưởng đến tốc độ tải tài nguyên LCP.

Loại bỏ hoàn toàn thời gian sử dụng mạng

Cách tốt nhất để giảm thời gian tải tài nguyên là loại bỏ mạng hoàn toàn khỏi quy trình này. Nếu bạn phân phát tài nguyên của mình bằng một chính sách kiểm soát bộ nhớ đệm hiệu quả, thì những khách truy cập yêu cầu những tài nguyên đó lần thứ hai sẽ được phân phát từ bộ nhớ đệm – điều này về cơ bản là thời lượng tải tài nguyên về cơ bản là bằng không!

Nếu tài nguyên LCP của bạn là một phông chữ trên web, thì ngoài việc giảm kích thước phông chữ web, bạn cũng nên cân nhắc xem mình có cần chặn hiển thị khi tải tài nguyên phông chữ trên web hay không. Nếu bạn đặt giá trị font-display của bất cứ giá trị nào khác ngoài auto hoặc block thì văn bản sẽ luôn hiển thị trong khi tải và LCP sẽ không bị chặn khi có yêu cầu mạng bổ sung.

Cuối cùng, nếu tài nguyên LCP nhỏ, bạn nên đặt nội tuyến các tài nguyên dưới dạng URL dữ liệu để loại bỏ yêu cầu mạng bổ sung. Tuy nhiên, việc sử dụng URL dữ liệu sẽ có cảnh báo vì tài nguyên không thể được lưu vào bộ nhớ đệm và trong một số trường hợp có thể khiến thời gian hiển thị lâu hơn do chi phí giải mã tăng thêm.

4. Giảm thời gian xuống byte đầu tiên

Mục tiêu của bước này là phân phối HTML ban đầu nhanh nhất có thể. Bước này được liệt kê cuối cùng vì đây thường là bước mà nhà phát triển có ít quyền kiểm soát nhất. Tuy nhiên, đó cũng là một trong những bước quan trọng nhất vì bước này ảnh hưởng trực tiếp đến mọi bước sau đó. Không có gì có thể xảy ra trên giao diện người dùng cho đến khi phần phụ trợ phân phối byte nội dung đầu tiên đó. Vì vậy, mọi việc bạn có thể làm để tăng tốc TTFB cũng sẽ cải thiện mọi chỉ số tải khác.

Một nguyên nhân phổ biến khiến TTFB chậm đối với một trang web nhanh là khách truy cập đến thông qua nhiều chuyển hướng, chẳng hạn như từ quảng cáo hoặc đường liên kết được rút ngắn. Luôn giảm thiểu số lần chuyển hướng mà khách truy cập phải chờ qua.

Một nguyên nhân phổ biến khác là khi không thể sử dụng nội dung đã lưu vào bộ nhớ đệm từ máy chủ biên CDN và tất cả yêu cầu phải được chuyển hoàn toàn về máy chủ gốc. Điều này có thể xảy ra nếu khách truy cập sử dụng các tham số URL duy nhất để phân tích – ngay cả khi các tham số đó không dẫn đến các trang khác nhau.

Để biết hướng dẫn cụ thể về cách tối ưu hoá TTFB, hãy tham khảo hướng dẫn tối ưu hoá TTFB.

Theo dõi bảng chi tiết LCP trong JavaScript

Thông tin về thời gian cho tất cả các phần phụ LCP được thảo luận trước đó có sẵn cho bạn trong JavaScript thông qua kết hợp các API hiệu suất sau:

Lợi ích của việc tính toán các giá trị thời gian này trong JavaScript là cho phép bạn gửi chúng đến nhà cung cấp phân tích hoặc ghi chúng vào các công cụ cho nhà phát triển để hỗ trợ gỡ lỗi và tối ưu hoá.

Ví dụ: ảnh chụp màn hình sau đây sử dụng phương thức performance.measure() từ API Thời gian người dùng để thêm thanh vào kênh Thời gian trong bảng điều khiển Hiệu suất Công cụ của Chrome cho nhà phát triển.

Các chỉ số Thời gian người dùng đo lường các danh mục con LCP được trực quan hoá trong Công cụ của Chrome cho nhà phát triển
Kênh đào tạo về Thời gian cho biết tiến trình của các danh mục con LCP.

Hình ảnh trong kênh Thời gian đặc biệt hữu ích khi được xem cùng với theo dõi MạngLuồng chính, vì bạn có thể xem nhanh những gì đang xảy ra trên trang trong các khoảng thời gian này.

Ngoài việc trực quan hoá các phần phụ LCP trong theo dõi thời gian, bạn cũng có thể sử dụng JavaScript để tính toán tỷ lệ phần trăm của mỗi phần phụ trong tổng thời gian LCP. Với thông tin đó, bạn có thể xác định xem các trang của mình có đáp ứng các thông tin chi tiết theo tỷ lệ phần trăm đề xuất như mô tả ở trên hay không.

Ảnh chụp màn hình này cho thấy một ví dụ ghi lại tổng thời gian của từng phần phụ LCP cũng như tỷ lệ phần trăm của tổng thời gian LCP trên bảng điều khiển.

Thời gian của danh mục con LCP, cũng như tỷ lệ phần trăm LCP của chúng, được in ra bảng điều khiển
Thời gian và tỷ lệ phần trăm cho danh mục phụ LCP.

Cả hai hình ảnh trực quan này đều được tạo bằng mã sau:

const LCP_SUB_PARTS = [
  'Time to first byte',
  'Resource load delay',
  'Resource load duration',
  'Element render delay',
];

new PerformanceObserver((list) => {
  const lcpEntry = list.getEntries().at(-1);
  const navEntry = performance.getEntriesByType('navigation')[0];
  const lcpResEntry = performance
    .getEntriesByType('resource')
    .filter((e) => e.name === lcpEntry.url)[0];

  // Ignore LCP entries that aren't images to reduce DevTools noise.
  // Comment this line out if you want to include text entries.
  if (!lcpEntry.url) return;

  // Compute the start and end times of each LCP sub-part.
  // WARNING! If your LCP resource is loaded cross-origin, make sure to add
  // the `Timing-Allow-Origin` (TAO) header to get the most accurate results.
  const ttfb = navEntry.responseStart;
  const lcpRequestStart = Math.max(
    ttfb,
    // Prefer `requestStart` (if TOA is set), otherwise use `startTime`.
    lcpResEntry ? lcpResEntry.requestStart || lcpResEntry.startTime : 0
  );
  const lcpResponseEnd = Math.max(
    lcpRequestStart,
    lcpResEntry ? lcpResEntry.responseEnd : 0
  );
  const lcpRenderTime = Math.max(
    lcpResponseEnd,
    // Use LCP startTime (the final LCP time) because there are sometimes
    // slight differences between loadTime/renderTime and startTime
    // due to rounding precision.
    lcpEntry ? lcpEntry.startTime : 0
  );

  // Clear previous measures before making new ones.
  // Note: due to a bug, this doesn't work in Chrome DevTools.
  LCP_SUB_PARTS.forEach((part) => performance.clearMeasures(part));

  // Create measures for each LCP sub-part for easier
  // visualization in the Chrome DevTools Performance panel.
  const lcpSubPartMeasures = [
    performance.measure(LCP_SUB_PARTS[0], {
      start: 0,
      end: ttfb,
    }),
    performance.measure(LCP_SUB_PARTS[1], {
      start: ttfb,
      end: lcpRequestStart,
    }),
    performance.measure(LCP_SUB_PARTS[2], {
      start: lcpRequestStart,
      end: lcpResponseEnd,
    }),
    performance.measure(LCP_SUB_PARTS[3], {
      start: lcpResponseEnd,
      end: lcpRenderTime,
    }),
  ];

  // Log helpful debug information to the console.
  console.log('LCP value: ', lcpRenderTime);
  console.log('LCP element: ', lcpEntry.element, lcpEntry.url);
  console.table(
    lcpSubPartMeasures.map((measure) => ({
      'LCP sub-part': measure.name,
      'Time (ms)': measure.duration,
      '% of LCP': `${
        Math.round((1000 * measure.duration) / lcpRenderTime) / 10
      }%`,
    }))
  );
}).observe({type: 'largest-contentful-paint', buffered: true});

Bạn có thể sử dụng mã này theo nguyên trạng để gỡ lỗi cục bộ hoặc sửa đổi mã để gửi dữ liệu này đến một nhà cung cấp phân tích. Nhờ đó, bạn có thể hiểu rõ hơn về dữ liệu chi tiết về LCP trên các trang cho người dùng thực.

Theo dõi bảng phân tích LCP bằng tiện ích Các chỉ số quan trọng về trang web

Tiện ích Các chỉ số quan trọng về trang web sẽ ghi nhật ký thời gian LCP, phần tử LCP và 4 phần phụ này trong bảng điều khiển, để bạn dễ dàng xem bảng chi tiết này.

Ảnh chụp màn hình ghi nhật ký trên bảng điều khiển của tiện ích Các chỉ số quan trọng về trang web cho thấy dấu thời gian của các phần phụ LCP
Bảng điều khiển Bảng điều khiển cho tiện ích Các chỉ số quan trọng về trang web cho thấy thông tin chi tiết về LCP.

Tóm tắt

LCP rất phức tạp và thời gian của LCP có thể chịu ảnh hưởng của một số yếu tố. Nhưng nếu bạn cho rằng việc tối ưu hoá LCP chủ yếu là tối ưu hoá tải tài nguyên LCP, thì việc này có thể đơn giản hoá đáng kể mọi thứ.

Ở cấp độ tổng quát, việc tối ưu hoá LCP có thể được tóm tắt qua 4 bước:

  1. Đảm bảo tài nguyên LCP bắt đầu tải càng sớm càng tốt.
  2. Đảm bảo phần tử LCP có thể hiển thị ngay khi tài nguyên của phần tử đó tải xong.
  3. Hãy giảm thời gian tải của tài nguyên LCP nhiều nhất có thể mà không làm giảm chất lượng.
  4. Phân phối tài liệu HTML ban đầu nhanh nhất có thể.

Nếu có thể làm theo các bước này trên trang của mình, thì bạn sẽ tự tin rằng mình đang mang lại trải nghiệm tải tối ưu cho người dùng và thấy điều đó được phản ánh trong điểm LCP thực tế của mình.