Tải từng phần hình ảnh ở cấp trình duyệt dành cho web

Tính năng tải từng phần tích hợp sẵn cuối cùng đã ra mắt!

Tính năng hỗ trợ tải từng phần ở cấp trình duyệt hiện đã được hỗ trợ trên web! Video này trình bày bản minh hoạ tính năng này:

Bạn có thể sử dụng thuộc tính loading để tải từng phần cho hình ảnh mà không cần phải viết mã tải từng phần tuỳ chỉnh hay sử dụng một thư viện JavaScript riêng. Hãy cùng tìm hiểu chi tiết nhé.

Khả năng tương thích với trình duyệt

Hỗ trợ trình duyệt

  • 77
  • 79
  • 75
  • 15,4

Các trình duyệt không hỗ trợ thuộc tính loading sẽ bỏ qua thuộc tính này mà không có tác dụng phụ.

Tại sao bạn nên tải từng phần ở cấp trình duyệt?

Theo Lưu trữ HTTP, hình ảnh là loại nội dung được yêu cầu nhiều nhất đối với hầu hết các trang web và thường chiếm nhiều băng thông hơn bất kỳ tài nguyên nào khác. Ở phân vị thứ 90, các trang web gửi hơn 5 MB hình ảnh trên máy tính và thiết bị di động. Sẽ rất nhiều ảnh về mèo.

Trước đây, có hai cách để trì hoãn việc tải hình ảnh ngoài màn hình:

Cả hai lựa chọn đều có thể cho phép nhà phát triển sử dụng chức năng tải từng phần và nhiều nhà phát triển đã tạo thư viện bên thứ ba để cung cấp các bản tóm tắt dễ sử dụng hơn. Tuy nhiên, với tính năng tải từng phần được trình duyệt hỗ trợ trực tiếp, bạn không cần phải có thư viện bên ngoài. Tính năng tải từng phần ở cấp trình duyệt cũng đảm bảo rằng tính năng tải chậm hình ảnh vẫn hoạt động ngay cả khi JavaScript bị tắt trên ứng dụng.

Thuộc tính loading

Chrome tải hình ảnh ở các mức độ ưu tiên khác nhau, tuỳ thuộc vào vị trí của hình ảnh so với khung nhìn của thiết bị. Hình ảnh bên dưới khung nhìn được tải với mức độ ưu tiên thấp hơn, nhưng chúng vẫn được tìm nạp khi tải trang.

Bạn có thể sử dụng thuộc tính loading để trì hoãn hoàn toàn việc tải những hình ảnh ngoài màn hình mà bạn truy cập được bằng cách cuộn:

<img src="image.png" loading="lazy" alt="…" width="200" height="200">

Sau đây là những giá trị được hỗ trợ cho thuộc tính loading:

  • lazy: Hoãn tải tài nguyên cho đến khi tài nguyên đạt đến khoảng cách đã tính toán từ khung nhìn.
  • eager: Hành vi tải mặc định của trình duyệt, tương tự như không bao gồm thuộc tính này và có nghĩa là hình ảnh sẽ được tải bất kể hình ảnh nằm ở đâu trên trang. Mặc dù đây là giá trị mặc định, nhưng bạn nên thiết lập rõ ràng giá trị này nếu công cụ của bạn tự động thêm loading="lazy" nếu không có giá trị rõ ràng hoặc nếu công cụ lint (tìm lỗi mã nguồn) của bạn phàn nàn nếu giá trị không được thiết lập rõ ràng.

Mối quan hệ giữa thuộc tính loading và mức độ ưu tiên tìm nạp

Giá trị eager chỉ đơn giản là một lệnh hướng dẫn tải hình ảnh như bình thường, không trì hoãn quá trình tải thêm nếu hình ảnh nằm ngoài màn hình. Thuộc tính này không ngụ ý rằng hình ảnh được tải nhanh hơn một hình ảnh khác không có thuộc tính loading="eager".

Trình duyệt ưu tiên tài nguyên dựa trên nhiều thông tin phỏng đoán và thuộc tính loading chỉ nêu rõ thời điểm tài nguyên hình ảnh được đưa vào hàng đợi, chứ không phải cách thức tài nguyên được ưu tiên trong hàng đợi đó. eager chỉ ngụ ý rằng các trình duyệt đang chờ đợi thông thường sử dụng theo mặc định.

Nếu muốn tăng mức độ ưu tiên tìm nạp của một hình ảnh quan trọng (ví dụ: hình ảnh LCP), thì bạn nên sử dụng Mức độ ưu tiên tìm nạp với fetchpriority="high".

Xin lưu ý rằng hình ảnh có loading="lazy"fetchpriority="high" sẽ vẫn bị trì hoãn khi không nằm ngoài màn hình, sau đó được tìm nạp ở mức độ ưu tiên cao khi gần như nằm trong khung nhìn. Trong trường hợp này, kết hợp nhiều khả năng sẽ được tìm nạp với mức độ ưu tiên cao, do đó, tổ hợp này không thực sự cần thiết cũng như không cần được sử dụng.

Ngưỡng khoảng cách từ khung nhìn

Tất cả hình ảnh trong màn hình đầu tiên (nghĩa là có thể xem ngay lập tức mà không cần cuộn) sẽ tải bình thường. Những thành phần nằm ngoài khung nhìn của thiết bị chỉ được tìm nạp khi người dùng cuộn gần chúng.

Việc triển khai tính năng tải từng phần của Chromium cố gắng đảm bảo rằng các hình ảnh ngoài màn hình được tải đủ sớm để các hình ảnh đó tải xong sau khi người dùng cuộn gần hình ảnh. Bằng cách tìm nạp hình ảnh lân cận thật kỹ trước khi chúng hiển thị trong khung nhìn, chúng tôi sẽ tối đa hoá khả năng hình ảnh đã được tải vào thời điểm hiển thị.

So với các thư viện tải từng phần của JavaScript, các ngưỡng tìm nạp hình ảnh cuộn vào khung hiển thị có thể được coi là vừa phải.

Ngưỡng khoảng cách là không cố định và thay đổi tuỳ thuộc vào một số yếu tố:

Bạn có thể tìm thấy các giá trị mặc định cho các loại kết nối hiệu quả khác nhau trong nguồn Chromium. Những con số này và thậm chí cả phương pháp tìm nạp chỉ khi đạt đến một khoảng cách nhất định từ khung nhìn, có thể thay đổi trong tương lai khi nhóm Chrome cải thiện các phương pháp phỏng đoán để xác định thời điểm bắt đầu tải.

Cải thiện khả năng tiết kiệm dữ liệu và ngưỡng khoảng cách từ khung nhìn

Kể từ tháng 7 năm 2020, Chrome đã có những điểm cải tiến đáng kể để điều chỉnh ngưỡng tải từng phần của hình ảnh theo khoảng cách từ khung nhìn của khung hình nhằm đáp ứng tốt hơn kỳ vọng của nhà phát triển.

Đối với các kết nối nhanh (4G), chúng tôi đã giảm ngưỡng khoảng cách từ khung nhìn của Chrome từ 3000px xuống còn 1250px. Còn trên các kết nối chậm hơn (3G trở xuống), chúng tôi đã thay đổi ngưỡng từ 4000px thành 2500px. Thay đổi này sẽ đạt được hai mục đích:

  • <img loading=lazy> hoạt động gần hơn với trải nghiệm do các thư viện tải từng phần JavaScript cung cấp.
  • Các ngưỡng mới về khoảng cách từ khung nhìn vẫn cho phép chúng tôi đảm bảo rằng hình ảnh có thể đã tải vào thời điểm người dùng cuộn đến.

Bạn có thể so sánh giữa ngưỡng khoảng cách từ điểm xem cũ và mới của một trong các bản minh hoạ của chúng tôi về kết nối nhanh (4G) ở bên dưới:

Ngưỡng cũ so với ngưỡng mới:

Các ngưỡng mới và cải tiến cho việc tải từng phần hình ảnh, giảm ngưỡng khoảng cách từ khung nhìn cho các kết nối nhanh từ 3000px xuống còn 1250px

và các ngưỡng mới so với LazySizes (thư viện tải từng phần của JS phổ biến):

Các ngưỡng mới về khoảng cách từ khung nhìn trong Chrome tải 90KB hình ảnh so với LazySizes tải trong 70KB trong cùng điều kiện mạng

Chúng tôi cam kết phối hợp với cộng đồng các tiêu chuẩn web để tìm ra sự phù hợp hơn về cách tiếp cận ngưỡng khoảng cách từ khung nhìn trên các trình duyệt.

Hình ảnh phải bao gồm các thuộc tính kích thước

Trong khi tải hình ảnh, trình duyệt sẽ không biết ngay kích thước của hình ảnh, trừ khi các kích thước này được chỉ định rõ ràng. Để cho phép trình duyệt đặt trước đủ không gian trên một trang cho hình ảnh, bạn nên tất cả thẻ <img> đều phải có cả thuộc tính widthheight. Nếu không chỉ định kích thước, thì hiện tượng thay đổi bố cục có thể xảy ra và dễ nhận thấy hơn trên các trang mất chút thời gian để tải.

<img src="image.png" loading="lazy" alt="…" width="200" height="200">

Ngoài ra, bạn có thể chỉ định trực tiếp giá trị của các biến này theo kiểu cùng dòng:

<img src="image.png" loading="lazy" alt="…" style="height:200px; width:200px;">

Phương pháp hay nhất về việc đặt phương diện sẽ áp dụng cho thẻ <img> bất kể thẻ có được tải từng phần hay không. Với phương pháp tải từng phần, phương pháp này có thể trở nên phù hợp hơn. Việc đặt widthheight trên hình ảnh trong các trình duyệt hiện đại cũng cho phép các trình duyệt dự đoán kích thước nội tại của chúng.

Trong hầu hết các trường hợp, hình ảnh vẫn tải từng phần nếu không bao gồm các phương diện, nhưng bạn nên lưu ý một vài trường hợp đặc biệt. Nếu không chỉ định widthheight, kích thước hình ảnh ban đầu sẽ là 0×0 pixel. Nếu bạn có một thư viện hình ảnh như vậy, trình duyệt có thể kết luận rằng tất cả các hình ảnh này vừa với khung nhìn ngay từ đầu vì mỗi hình ảnh gần như không chiếm không gian và không có hình ảnh nào được đẩy ra khỏi màn hình. Trong trường hợp này, trình duyệt xác định rằng tất cả các trang đều hiển thị cho người dùng và quyết định tải mọi nội dung.

Ngoài ra, việc chỉ định kích thước hình ảnh giúp giảm nguy cơ thay đổi bố cục. Nếu bạn không thể bao gồm các kích thước cho hình ảnh của mình, thì việc tải từng phần có thể là sự đánh đổi giữa việc tiết kiệm tài nguyên mạng và có nguy cơ thay đổi bố cục.

Mặc dù tính năng tải từng phần trong Chromium được triển khai theo cách làm cho hình ảnh có thể được tải sau khi hiển thị, nhưng vẫn có khả năng là các hình ảnh đó vẫn chưa được tải. Trong trường hợp này, việc thiếu các thuộc tính widthheight trên những hình ảnh đó sẽ làm tăng mức ảnh hưởng của các thuộc tính này đến Điểm số tổng hợp về mức thay đổi bố cục.

Hình ảnh được xác định bằng phần tử <picture> cũng có thể được tải từng phần:

<picture>
  <source media="(min-width: 800px)" srcset="large.jpg 1x, larger.jpg 2x">
  <img src="photo.jpg" loading="lazy">
</picture>

Mặc dù trình duyệt sẽ quyết định sẽ tải hình ảnh nào từ bất kỳ phần tử <source> nào, nhưng bạn chỉ cần thêm thuộc tính loading vào phần tử <img> dự phòng.

Tránh tải từng phần hình ảnh trong khung nhìn có thể nhìn thấy đầu tiên

Bạn nên tránh đặt loading=lazy cho bất kỳ hình ảnh nào trong khung nhìn hiển thị đầu tiên. Điều này đặc biệt cần thiết đối với hình ảnh LCP. Xem bài viết Ảnh hưởng đến hiệu suất của quá trình tải từng phần để biết thêm thông tin.

Bạn chỉ nên thêm loading=lazy vào những hình ảnh được đặt dưới màn hình đầu tiên, nếu có thể. Bạn có thể tìm nạp hình ảnh được tải ngay lập tức, trong khi hình ảnh được tải từng phần mà trình duyệt hiện phải đợi cho đến khi biết được vị trí của hình ảnh trên trang – dựa vào IntersectionObserver để có sẵn.

Nói chung, bất kỳ hình ảnh nào trong khung nhìn đều phải được tải nhanh chóng bằng các chế độ mặc định của trình duyệt. Bạn không cần chỉ định loading=eager cho trường hợp này đối với hình ảnh trong khung nhìn.

<!-- visible in the viewport -->
<img src="product-1.jpg" alt="..." width="200" height="200">
<img src="product-2.jpg" alt="..." width="200" height="200">
<img src="product-3.jpg" alt="..." width="200" height="200">

<!-- offscreen images -->
<img src="product-4.jpg" loading="lazy" alt="..." width="200" height="200">
<img src="product-5.jpg" loading="lazy" alt="..." width="200" height="200">
<img src="product-6.jpg" loading="lazy" alt="..." width="200" height="200">

Xuống cấp nhẹ

Các trình duyệt không hỗ trợ thuộc tính loading sẽ bỏ qua sự hiện diện này. Mặc dù các trình duyệt này tất nhiên sẽ không nhận được lợi ích của tính năng tải từng phần, nhưng việc bao gồm thuộc tính này không ảnh hưởng tiêu cực đến trình duyệt.

Câu hỏi thường gặp

Google có dự định tự động tải từng phần hình ảnh trong Chrome không?

Trước đây, Chromium tự động tải từng phần bất kỳ hình ảnh nào rất phù hợp để trì hoãn nếu Chế độ Lite được bật trên Chrome dành cho Android và thuộc tính loading không được cung cấp hoặc không được đặt thành loading="auto". Tuy nhiên, Chế độ Lite đã ngừng hoạt động (cũng như loading="auto" không theo chuẩn) và hiện chưa có kế hoạch nào để tự động tải từng phần của hình ảnh trong Chrome.

Tôi có thể thay đổi khoảng cách của hình ảnh trước khi kích hoạt một lượt tải không?

Các giá trị này được cố định giá trị trong mã và không thể thay đổi thông qua API. Tuy nhiên, các ngưỡng này có thể thay đổi trong tương lai khi các trình duyệt thử nghiệm với nhiều biến và khoảng cách ngưỡng.

Hình nền CSS có thể tận dụng thuộc tính loading không?

Không, hiện chỉ có thể sử dụng công cụ này với thẻ <img>.

Có nhược điểm nào đối với việc tải từng phần hình ảnh trong khung nhìn của thiết bị không?

Sẽ an toàn hơn nếu bạn tránh đặt loading=lazy vào hình ảnh trong màn hình đầu tiên vì Chrome sẽ không tải trước loading=lazy hình ảnh trong trình quét tải trước và cũng sẽ trì hoãn việc tìm nạp những hình ảnh đó cho đến khi tất cả bố cục hoàn chỉnh. Hãy xem phần Tránh tải từng phần hình ảnh trong khung nhìn hiển thị đầu tiên để biết thêm thông tin.

Việc sử dụng loading="lazy" có thể ngăn hình ảnh được tải khi chúng không hiển thị, nhưng trong phạm vi khoảng cách đã tính toán. Ví dụ: Chrome, Safari và Firefox không tải hình ảnh bằng cách sử dụng kiểu display: none;, trên phần tử hình ảnh hoặc phần tử mẹ. Tuy nhiên, các kỹ thuật khác để ẩn hình ảnh (chẳng hạn như sử dụng định kiểu opacity:0) vẫn sẽ dẫn đến việc hình ảnh được tải. Hãy luôn kiểm tra kỹ lưỡng phương thức triển khai để đảm bảo phương thức triển khai hoạt động như dự kiến.

Nếu tôi đang sử dụng thư viện của bên thứ ba hoặc một tập lệnh để tải từng phần hình ảnh thì sao?

Với sự hỗ trợ đầy đủ cho tính năng tải từng phần gốc hiện đã có trong các trình duyệt hiện đại, bạn nên xem xét lại nếu vẫn cần thư viện hoặc tập lệnh của bên thứ ba để tải từng phần hình ảnh.

Một lý do để tiếp tục sử dụng thư viện của bên thứ ba cùng với loading="lazy" là để cung cấp polyfill cho các trình duyệt không hỗ trợ thuộc tính này hoặc để có nhiều quyền kiểm soát hơn đối với thời điểm kích hoạt tính năng tải từng phần.

Làm cách nào để xử lý các trình duyệt không hỗ trợ tải từng phần?

Tạo một đoạn mã polyfill hoặc sử dụng một thư viện của bên thứ ba để tải từng phần hình ảnh trên trang web của bạn. Bạn có thể sử dụng thuộc tính loading để phát hiện xem tính năng này có được hỗ trợ trong trình duyệt hay không:

if ('loading' in HTMLImageElement.prototype) {
  // supported in browser
} else {
  // fetch polyfill/third-party library
}

Ví dụ: lazysizes là một thư viện JavaScript tải từng phần phổ biến. Bạn chỉ có thể phát hiện tính năng hỗ trợ cho thuộc tính loading để tải từng phần dưới dạng thư viện dự phòng khi loading không được hỗ trợ. Hàm này hoạt động như sau:

  • Thay thế <img src> bằng <img data-src> để tránh tải ngay trong các trình duyệt không được hỗ trợ. Nếu thuộc tính loading được hỗ trợ, hãy hoán đổi data-src cho src.
  • Nếu loading không được hỗ trợ, hãy tải một bản dự phòng (lazysizes) và khởi động bản dự phòng đó. Theo các tài liệu về lazysizes, bạn sử dụng lớp lazyload như một cách để chỉ báo tải từng phần của từng hình ảnh.
<!-- Let's load this in-viewport image normally -->
<img src="hero.jpg" alt="…">

<!-- Let's lazy-load the rest of these images -->
<img data-src="unicorn.jpg" alt="…" loading="lazy" class="lazyload">
<img data-src="cats.jpg" alt="…" loading="lazy" class="lazyload">
<img data-src="dogs.jpg" alt="…" loading="lazy" class="lazyload">

<script>
  if ('loading' in HTMLImageElement.prototype) {
    const images = document.querySelectorAll('img[loading="lazy"]');
    images.forEach(img => {
      img.src = img.dataset.src;
    });
  } else {
    // Dynamically import the LazySizes library
    const script = document.createElement('script');
    script.src =
      'https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js';
    document.body.appendChild(script);
  }
</script>

Đây là bản minh hoạ của mẫu này. Hãy dùng thử trong trình duyệt cũ hơn để xem tính năng dự phòng hoạt động.

Trình duyệt có hỗ trợ tính năng tải từng phần cho iframe không?

Hỗ trợ trình duyệt

  • 77
  • 79
  • 121
  • 16,4

<iframe loading=lazy> cũng đã được chuẩn hoá và đã được triển khai trong Chromium và Safari. Tính năng này cho phép bạn tải từng phần của iframe bằng cách sử dụng thuộc tính loading. Xem bài viết riêng này về tính năng tải từng phần của iframe để biết thêm thông tin.

Tải từng phần ở cấp trình duyệt ảnh hưởng như thế nào đến quảng cáo trên trang web?

Tất cả quảng cáo được hiển thị cho người dùng dưới dạng tải từng phần của hình ảnh hoặc iframe giống như mọi hình ảnh hoặc iframe khác.

Hình ảnh được xử lý như thế nào khi in trang web?

Tất cả hình ảnh và iframe đều được tải ngay lập tức nếu trang được in. Hãy xem vấn đề #875403 để biết chi tiết.

Lighthouse có nhận ra tính năng tải từng phần ở cấp trình duyệt không?

Lighthouse 6.0 trở lên tính đến các phương pháp tải từng phần hình ảnh ngoài màn hình có thể sử dụng các ngưỡng khác nhau, cho phép họ vượt qua bài kiểm tra Trì hoãn hình ảnh ngoài màn hình.

Kết luận

Việc tích hợp tính năng hỗ trợ tải từng phần hình ảnh có thể giúp bạn cải thiện hiệu suất trang web dễ dàng hơn rất nhiều.

Bạn có nhận thấy hành vi bất thường nào khi bật tính năng này trong Chrome không? Báo cáo lỗi!