Tải từng phần hình ảnh và các phần tử <iframe>

Hình ảnh và các phần tử <iframe> thường tiêu tốn nhiều băng thông hơn các loại tài nguyên khác. Đối với các phần tử <iframe>, việc tải và hiển thị các trang trong các phần tử đó có thể mất thêm thời gian xử lý.

Trong trường hợp hình ảnh tải từng phần, việc trì hoãn tải hình ảnh bên ngoài khung nhìn ban đầu có thể hữu ích trong việc giảm tranh chấp băng thông cho các tài nguyên quan trọng hơn trong khung nhìn ban đầu. Điều này có thể cải thiện Thời gian hiển thị nội dung lớn nhất (LCP) trên một trang trong một số trường hợp kết nối mạng kém và băng thông được phân bổ lại có thể giúp các đề xuất LCP tải và hiển thị nhanh hơn.

Nếu quan ngại các phần tử <iframe>, bạn có thể cải thiện Lượt tương tác với Nội dung hiển thị tiếp theo (INP) của một trang trong quá trình khởi động bằng cách tải từng phần. Lý do là <iframe> là một tài liệu HTML hoàn toàn riêng biệt có các tài nguyên phụ riêng. Mặc dù các phần tử <iframe> có thể chạy trong một quy trình riêng, nhưng việc các phần tử này chia sẻ một quy trình với các luồng khác cũng thường xảy ra. Điều này có thể tạo ra điều kiện khiến các trang trở nên kém phản hồi hơn đối với hoạt động đầu vào của người dùng.

Do đó, việc trì hoãn việc tải các hình ảnh ngoài màn hình và các phần tử <iframe> là một kỹ thuật đáng để thử và đòi hỏi mức độ nỗ lực khá thấp để mang lại hiệu suất tương đối tốt. Mô-đun này giải thích về việc tải từng phần hai loại phần tử này để mang lại trải nghiệm người dùng nhanh hơn và tốt hơn trong giai đoạn khởi động quan trọng của trang.

Tải từng phần hình ảnh bằng thuộc tính loading

Bạn có thể thêm thuộc tính loading vào các phần tử <img> để cho trình duyệt biết cách tải:

  • "eager" thông báo cho trình duyệt rằng hình ảnh phải được tải ngay lập tức, ngay cả khi hình ảnh nằm ngoài khung nhìn ban đầu. Đây cũng là giá trị mặc định cho thuộc tính loading.
  • "lazy" trì hoãn việc tải một hình ảnh cho đến khi hình ảnh đó nằm trong một khoảng cách đã đặt tính từ khung nhìn hiển thị. Khoảng cách này sẽ khác nhau tuỳ theo trình duyệt, nhưng thường được đặt ở mức đủ lớn để hình ảnh tải được vào thời điểm người dùng cuộn đến.

Ngoài ra, bạn cũng cần lưu ý rằng nếu đang sử dụng phần tử <picture>, bạn vẫn phải áp dụng thuộc tính loading cho phần tử con <img>, không phải cho chính phần tử <picture>. Nguyên nhân là do phần tử <picture> là một vùng chứa chứa các phần tử <source> bổ sung trỏ đến nhiều hình ảnh đề xuất và đề xuất mà trình duyệt chọn sẽ được áp dụng trực tiếp cho phần tử con <img>.

Không tải từng phần hình ảnh trong khung nhìn ban đầu

Bạn chỉ nên thêm thuộc tính loading="lazy" vào các phần tử <img> đặt bên ngoài khung nhìn ban đầu. Tuy nhiên, việc biết vị trí chính xác của một phần tử tương đối trong khung nhìn trước khi trang được hiển thị có thể rất phức tạp. Bạn phải xem xét nhiều kích thước khung nhìn, tỷ lệ khung hình và thiết bị.

Ví dụ: khung nhìn trên máy tính có thể khá khác so với khung nhìn trên điện thoại di động vì khung nhìn này hiển thị nhiều không gian dọc hơn, có thể vừa với hình ảnh trong khung nhìn ban đầu không xuất hiện trong khung nhìn ban đầu của thiết bị thực tế nhỏ hơn. Máy tính bảng được sử dụng ở hướng dọc cũng hiển thị một lượng không gian dọc đáng kể, thậm chí có thể nhiều hơn một số thiết bị máy tính để bàn.

Tuy nhiên, trong một số trường hợp, rõ ràng là bạn không nên áp dụng loading="lazy". Ví dụ: bạn nên bỏ thuộc tính loading="lazy" khỏi các phần tử <img> trong trường hợp hình ảnh chính hoặc các trường hợp sử dụng hình ảnh khác mà phần tử <img> có nhiều khả năng sẽ xuất hiện trong màn hình đầu tiên hoặc gần đầu bố cục trên bất cứ thiết bị nào. Điều này thậm chí còn quan trọng hơn đối với những hình ảnh có khả năng là ứng viên LCP.

Các hình ảnh tải từng phần cần phải chờ trình duyệt hoàn tất bố cục để biết liệu vị trí cuối cùng của hình ảnh có nằm trong khung nhìn hay không. Điều này có nghĩa là nếu phần tử <img> trong khung nhìn hiển thị có thuộc tính loading="lazy", thì thuộc tính này chỉ được yêu cầu sau khi tất cả CSS được tải xuống, phân tích cú pháp và áp dụng cho trang, thay vì được tìm nạp ngay khi trình quét tải trước phát hiện thấy thuộc tính đó trong mã đánh dấu thô.

thuộc tính loading trên phần tử <img> được hỗ trợ trên tất cả các trình duyệt chính, nên bạn không cần dùng JavaScript để tải từng phần hình ảnh, vì việc thêm JavaScript bổ sung vào một trang để cung cấp các tính năng mà trình duyệt đã cung cấp sẽ ảnh hưởng đến các khía cạnh khác của hiệu suất trang (chẳng hạn như INP).

Bản minh hoạ tải từng phần hình ảnh

Tải từng phần các phần tử <iframe>

Tải từng phần các phần tử <iframe> cho đến khi chúng hiển thị trong khung nhìn có thể giúp tiết kiệm dữ liệu quan trọng và cải thiện việc tải tài nguyên quan trọng cần thiết để trang cấp cao nhất tải. Ngoài ra, vì các phần tử <iframe> về cơ bản là toàn bộ tài liệu HTML được tải trong một tài liệu cấp cao nhất, nên các phần tử này có thể bao gồm một số lượng lớn tài nguyên phụ — đặc biệt là JavaScript — có thể ảnh hưởng đáng kể đến INP của trang nếu các tác vụ trong các khung đó đòi hỏi thời gian xử lý đáng kể.

Nội dung nhúng của bên thứ ba là một trường hợp sử dụng phổ biến cho các phần tử <iframe>. Ví dụ: trình phát video được nhúng hoặc bài đăng trên mạng xã hội thường sử dụng các phần tử <iframe> và các phần tử này thường đòi hỏi một số lượng đáng kể tài nguyên phụ, điều này cũng có thể dẫn đến tranh chấp băng thông cho các tài nguyên trên trang cấp cao nhất. Ví dụ: tải từng phần của video nhúng trên YouTube sẽ giúp tiết kiệm hơn 500 KiB trong lần tải trang ban đầu, trong khi tải từng phần Trình bổ trợ nút Thích của Facebook sẽ giúp tiết kiệm hơn 200 KiB, hầu hết trong số đó là JavaScript.

Dù bằng cách nào, bất cứ khi nào có <iframe> dưới màn hình đầu tiên trên một trang, bạn nên đặc biệt cân nhắc việc tải từng phần nếu không cần thiết phải tải trước, vì làm như vậy có thể cải thiện đáng kể trải nghiệm người dùng.

Thuộc tính loading cho các phần tử <iframe>

Thuộc tính loading trên các phần tử <iframe> cũng được hỗ trợ trong tất cả các trình duyệt chính. Giá trị của thuộc tính loading và hành vi của thuộc tính này giống như với các phần tử <img> sử dụng thuộc tính loading:

  • "eager" là giá trị mặc định. Phần tử này thông báo cho trình duyệt tải HTML của phần tử <iframe> và các tài nguyên phụ của phần tử đó ngay lập tức.
  • "lazy" trì hoãn việc tải HTML của phần tử <iframe> và các tài nguyên phụ của phần tử đó cho đến khi phần tử này nằm trong khoảng cách xác định trước tính từ khung nhìn.

Bản minh hoạ iframe tải từng phần

Mặt tiền

Thay vì tải nội dung nhúng ngay lập tức trong khi tải trang, bạn có thể tải nội dung nhúng đó theo yêu cầu để phản hồi một tương tác của người dùng. Bạn có thể thực hiện việc này bằng cách hiển thị hình ảnh hoặc một phần tử HTML thích hợp khác cho đến khi người dùng tương tác với phần tử đó. Khi người dùng tương tác với phần tử, bạn có thể thay thế phần tử đó bằng nội dung nhúng của bên thứ ba. Kỹ thuật này được gọi là mặt tiền.

Một trường hợp sử dụng phổ biến cho thành phần hình ảnh là hoạt động nhúng video từ các dịch vụ của bên thứ ba. Trong đó, việc nhúng có thể liên quan đến việc tải nhiều tài nguyên phụ bổ sung và có thể tốn kém (chẳng hạn như JavaScript) ngoài chính nội dung video. Trong trường hợp như vậy, trừ phi có nhu cầu tự động phát video, thì việc nhúng video sẽ yêu cầu người dùng tương tác với video trước khi phát bằng cách nhấp vào nút phát.

Đây là cơ hội tốt để hiển thị hình ảnh tĩnh tương tự về mặt hình ảnh với video được nhúng và tiết kiệm đáng kể băng thông trong quá trình này. Sau khi người dùng nhấp vào hình ảnh, hình ảnh đó sẽ được thay thế bằng thao tác nhúng <iframe> thực tế. Thao tác này sẽ kích hoạt HTML của phần tử <iframe> bên thứ ba và các tài nguyên phụ của phần tử đó để bắt đầu tải xuống.

Ngoài việc cải thiện lượt tải trang ban đầu, một ưu điểm khác là nếu người dùng không bao giờ phát video, thì tài nguyên cần thiết để phân phối video sẽ không bao giờ được tải xuống. Đây là một mẫu hình hiệu quả vì nó đảm bảo người dùng chỉ tải những gì họ thực sự muốn tải xuống mà không đưa ra các giả định sai lầm về nhu cầu của họ.

Tiện ích trò chuyện là một trường hợp sử dụng tuyệt vời khác cho kỹ thuật thành phần tượng trưng. Hầu hết các tiện ích trò chuyện đều tải xuống một lượng lớn JavaScript có thể ảnh hưởng tiêu cực đến khả năng tải trang và khả năng phản hồi hoạt động đầu vào của người dùng. Tương tự như khi tải trước nội dung, chi phí sẽ phát sinh tại thời điểm tải. Tuy nhiên, đối với tiện ích trò chuyện, không phải người dùng nào cũng có ý định tương tác với tiện ích đó.

Mặt khác, bạn có thể thay thế nút "Start Chat" (Bắt đầu trò chuyện) của bên thứ ba bằng một nút giả. Khi người dùng tương tác có ý nghĩa với tiện ích trò chuyện đó (chẳng hạn như giữ con trỏ trên tiện ích đó trong một khoảng thời gian hợp lý hoặc bằng một lần nhấp), tiện ích trò chuyện thực tế, đang hoạt động sẽ được đặt vào vị trí khi người dùng cần.

Bạn có thể xây dựng mặt tiền của riêng mình, nhưng chúng tôi có các tuỳ chọn nguồn mở dành cho các bên thứ ba phổ biến hơn, chẳng hạn như lite-youtube-embed cho video trên YouTube, lite-vimeo-embed cho video trên Vimeo và React Live Chat Loader (Trình tải trò chuyện trực tiếp) cho tiện ích trò chuyện.

Thư viện tải từng phần JavaScript

Nếu cần tải từng phần các phần tử <video>, hình ảnh phần tử <video> poster, hình ảnh do thuộc tính CSS background-image hoặc các phần tử không được hỗ trợ khác tải, bạn có thể thực hiện việc này bằng một giải pháp tải từng phần dựa trên JavaScript, chẳng hạn như lazysizes hoặc yall.js, vì tải từng phần của các loại tài nguyên này không phải là một tính năng cấp trình duyệt.

Cụ thể, việc tự động phát và lặp lại các phần tử <video> không có bản âm thanh là phương án thay thế hiệu quả hơn nhiều so với việc sử dụng ảnh GIF động, thường có thể lớn hơn nhiều lần so với tài nguyên video có chất lượng hình ảnh tương đương. Mặc dù vậy, những video này vẫn có thể rất đáng kể về mặt băng thông. Vì vậy, việc tải từng phần của những video này là một tính năng tối ưu hoá bổ sung, giúp giảm thiểu lãng phí băng thông.

Hầu hết các thư viện này hoạt động thông qua Intersection Observer APIMutation Observer API nếu HTML của trang thay đổi sau lần tải đầu tiên để nhận diện thời điểm một phần tử đi vào khung nhìn của người dùng. Nếu hình ảnh hiển thị hoặc đang hiển thị trong khung nhìn, thì thư viện JavaScript sẽ thay thế thuộc tính không chuẩn (thường là data-src hoặc một thuộc tính tương tự) bằng thuộc tính chính xác, chẳng hạn như src.

Giả sử bạn có một video thay thế ảnh GIF động, nhưng bạn muốn tải từng phần video đó bằng một giải pháp JavaScript. Bạn có thể làm việc này với yall.js với mẫu đánh dấu sau:

<!-- The autoplay, loop, muted, and playsinline attributes are to
     ensure the video can autoplay without user intervention. -->
<video class="lazy" autoplay loop muted playsinline width="320" height="480">
  <source data-src="video.webm" type="video/webm">
  <source data-src="video.mp4" type="video/mp4">
</video>

Theo mặc định, yall.js tuân thủ tất cả các phần tử HTML đủ điều kiện có lớp "lazy". Sau khi yall.js được tải và thực thi trên trang, video sẽ không tải cho đến khi người dùng cuộn video vào khung nhìn. Khi đó, các thuộc tính data-src trên các phần tử con <source> của phần tử <video> sẽ được hoán đổi thành thuộc tính src. Thuộc tính này sẽ gửi yêu cầu tải video xuống và tự động bắt đầu phát video.

Kiểm tra kiến thức

Đâu là giá trị mặc định cho thuộc tính loading của cả hai phần tử <img><iframe>?

"eager"
Chính xác!
"lazy"
Hãy thử lại.

Khi nào nên sử dụng các giải pháp tải từng phần dựa trên JavaScript?

Đối với mọi tài nguyên có thể tải từng phần.
Hãy thử lại.
Đối với các tài nguyên không hỗ trợ thuộc tính loading, chẳng hạn như trong trường hợp video tự động phát có mục đích thay thế hình ảnh động hoặc để tải từng phần hình ảnh áp phích của phần tử <video>.
Chính xác!

Khi nào thành phần tượng trưng là một kỹ thuật hữu ích?

Đối với mọi nội dung nhúng của bên thứ ba sử dụng lượng dữ liệu đáng kể, bất kể nhu cầu của người dùng.
Hãy thử lại.
Đối với mọi tệp nhúng của bên thứ ba, trong đó tài nguyên cần thiết để tải không chỉ đáng kể mà còn có xác suất khá lớn là không phải người dùng nào cũng có thể tương tác với những tài nguyên đó.
Chính xác!

Tiếp theo: Tìm nạp trước và kết xuất trước

Giờ đây, khi đã xử lý hình ảnh tải từng phần và phần tử <iframe>, bạn đã dễ dàng đảm bảo rằng các trang có thể tải nhanh hơn trong khi vẫn đáp ứng nhu cầu của người dùng. Tuy nhiên, có những trường hợp bạn có thể tải tài nguyên theo cách suy đoán. Trong mô-đun tiếp theo, hãy tìm hiểu về cách tìm nạp trước và kết xuất trước, cũng như cách các kỹ thuật này (khi được sử dụng cẩn thận) có thể giúp tăng đáng kể tốc độ điều hướng đến các trang tiếp theo bằng cách tải trước.