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

Hỗ trợ trình duyệt

  • 77
  • 79
  • 75
  • 15,4

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 hoặc sử dụng một thư viện JavaScript riêng. Đây là bản minh hoạ về tính năng này:

Hình ảnh tải từng phần sẽ tải khi người dùng cuộn qua trang.

Trang này trình bày chi tiết về cách triển khai tính năng tải từng phần trong trình duyệt.

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

Theo Kho lưu trữ HTTP, hình ảnh là loại thành phần đượ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 mọi tài nguyên 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.

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 đưa vào hành vi tải từng phần, và nhiều nhà phát triển đã tạo các thư viện bên thứ ba để cung cấp các bản trừu tượng thậm chí còn 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 hình ảnh vẫn hoạt động ngay cả khi ứng dụng tắt JavaScript. Tuy nhiên, xin lưu ý rằng quá trình tải chỉ bị trì hoãn khi JavaScript được bật.

Thuộc tính loading

Chrome tải hình ảnh ở nhiều mức độ ưu tiên, tuỳ thuộc vào vị trí của hình ảnh so với khung nhìn của thiết bị. Các 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 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 hình ảnh ngoài màn hình:

<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 so với khung nhìn.
  • eager: Hành vi tải mặc định của trình duyệt, tương tự như hành vi 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 ở vị trí nào trên trang. Đây là giá trị mặc định, nhưng bạn nên thiết lập một cách rõ ràng nếu công cụ của bạn tự động thêm loading="lazy" khi không có giá trị rõ ràng hoặc nếu công cụ linter 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 là một lệnh hướng dẫn tải hình ảnh như bình thường, không trì hoãn thêm hoạt động tải nếu hình ảnh nằm ngoài màn hình. Hình ảnh này tải không nhanh hơn một hình ảnh khác không có thuộc tính loading.

Nếu bạn 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), hãy sử dụng Mức độ ưu tiên tìm nạp với fetchpriority="high".

Hình ảnh có loading="lazy"fetchpriority="high" vẫn bị trễ khi nằm ngoài màn hình, sau đó được tìm nạp với mức độ ưu tiên cao khi gần như nằm trong khung nhìn. Sự kết hợp này không thực sự cần thiết vì trình duyệt vẫn có khả năng tải hình ảnh đó với mức độ ưu tiên cao.

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

Tất cả hình ảnh có thể xem ngay lập tức mà không cần cuộn như bình thường. Hình ảnh xa bên dướ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 để hình ảnh tải xong vào thời điểm người dùng cuộn đến bằng cách tìm nạp các hình ảnh đó trước khi hiển thị trong khung nhìn.

Ngưỡng khoảng cách sẽ thay đổi tuỳ thuộc vào các yếu tố sau:

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. Bạn có thể thử nghiệm với các ngưỡng khác nhau này bằng cách điều tiết mạng trong Công cụ cho nhà phát triển.

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

Vào tháng 7 năm 2020, Chrome đã thực hiện 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 tính theo khoảng cách từ khung nhìn 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 có nghĩa là hình ảnh có thể đã được 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ừ khung nhìn 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 tính năng tải từng phần của 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.
So sánh các ngưỡng cũ so với ngưỡng mới được dùng cho phương thức tải từng phần gốc.

và các ngưỡng mới so với LazySizes (thư viện tải từng phần JavaScript 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.
So sánh các ngưỡng dùng cho tính năng tải từng phần trong Chrome và LazySizes.

Cung cấp các thuộc tính kích thước hình ảnh

Trong khi tải một hình ảnh, trình duyệt sẽ không biết ngay kích thước của hình ảnh, trừ phi các kích thước đó được chỉ định rõ ràng. Để trình duyệt đặt trước đủ không gian trên một trang cho hình ảnh và tránh tình trạng thay đổi bố cục gây phiền toái, bạn nên thêm các thuộc tính widthheight vào tất cả các thẻ <img>.

<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 để đặt kích thước là áp dụng cho thẻ <img> bất kể bạn có tải từng phần hay không, nhưng tính năng tải từng phần có thể khiến thẻ trở nên quan trọng hơn.

Tính năng Tải từng phần trong Chromium được triển khai theo cách giúp hình ảnh có nhiều khả năng được tải ngay khi hiển thị, nhưng vẫn có khả năng các hình ảnh đó sẽ không tải đúng thời điểm. Nếu điều đó xảy ra, việc không chỉ định widthheight trên hình ảnh sẽ làm tăng ảnh hưởng của hai yếu tố này đến Điểm số tổng hợp về mức thay đổi bố cục. Nếu bạn không thể chỉ định kích thước hình ảnh, thì tính năng tải từng phần có thể tiết kiệm tài nguyên mạng trước nguy cơ gây ra tình trạng thay đổi bố cục tăng lên.

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

Để xem ví dụ về cách loading hoạt động với số lượng lớn hình ảnh, hãy tham khảo bản minh hoạ này.

Bạn cũng có thể tải từng phần hình ảnh mà bạn đã xác định bằng cách sử dụng phần tử <picture>:

<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 quyết định hình ảnh nào sẽ tải từ bất kỳ phần tử <source> nào, nhưng bạn chỉ cần thêm loading vào phần tử <img> dự phòng.

Luôn tải sớm hình ảnh hiển thị trong khung nhìn đầu tiên

Đối với các hình ảnh xuất hiện khi người dùng tải trang lần đầu tiên (đặc biệt là đối với hình ảnh LCP), hãy sử dụng chế độ tải nhanh mặc định của trình duyệt để các hình ảnh đó có thể truy cập được ngay. Để biết thêm thông tin, hãy xem Ảnh hưởng của việc tải từng phần về hiệu suất.

Chỉ sử dụng loading=lazy cho hình ảnh bên ngoài khung nhìn ban đầu. Trình duyệt không thể tải từng phần một hình ảnh cho đến khi biết rõ vị trí của hình ảnh đó trên trang, điều này khiến hình ảnh tải chậm hơ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 thuộc tính này. Phương thức tải từng phần không mang lại lợi ích, nhưng việc sử dụng tính năng này không gây ra tác động tiêu cực nào.

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

Tôi có thể 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 mọi hình ảnh hoàn toàn phù hợp với việc 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 đặt thành loading="auto". Tuy nhiên, Chế độ Lite và loading="auto" đã ngừng hoạt động và chúng tôi không có kế hoạch tự động tải từng phần của hình ảnh vào Chrome.

Tôi có thể thay đổi khoảng cách giữa hình ảnh và khung nhìn trước khi 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 chỉ số này có thể thay đổi trong tương lai khi các trình duyệt thử nghiệm với các biến và khoảng cách ngưỡng khác nhau.

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

Không, bạn chỉ có thể sử dụng với thẻ <img>.

Việc sử dụng loading="lazy" có thể ngăn việc tải hình ảnh khi hình ảnh không hiển thị nhưng nằm trong khoảng cách đã tính. Những hình ảnh này có thể ở sau một băng chuyền hoặc bị CSS ẩn đối với một số kích thước màn hình nhất định. 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 trên phần tử mẹ. Tuy nhiên, các kỹ thuật ẩn hình ảnh khác, chẳng hạn như sử dụng kiểu opacity:0, vẫn khiến trình duyệt tải hình ảnh. Hãy luôn kiểm thử kỹ lưỡng phương thức triển khai để đảm bảo phương án hoạt động như dự kiến.

Chrome 121 đã thay đổi hành vi đối với hình ảnh cuộn ngang như băng chuyền. Các luồng này hiện sử dụng cùng các ngưỡng như cuộn dọc. Điều này có nghĩa là đối với trường hợp sử dụng băng chuyền, hình ảnh sẽ được tải trước khi hiển thị trong khung nhìn. Điều này có nghĩa là người dùng ít có khả năng nhận thấy hoạt động tải hình ảnh, nhưng đổi lại sẽ có nhiều lượt tải xuống hơn. Sử dụng bản minh hoạ Tải từng phần theo chiều ngang để so sánh hành vi trong Chrome so với Safari và Firefox.

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 khả năng hỗ trợ đầy đủ cho tính năng tải từng phần tích hợp sẵn trong các trình duyệt hiện đại, bạn có thể không 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ó thêm quyền kiểm soát đố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? {browsers-dont-support}

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 để xem trình duyệt có hỗ trợ tính năng này 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 tải từng phần JavaScript 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 từ lazysize và khởi động nó, sử dụng lớp lazyload để cho biết hình ảnh nào cần tải từng phần:
<!-- 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á. Tính năng này cho phép bạn tải từng phần iframe bằng thuộc tính loading. Để biết thêm thông tin, hãy xem Đã đến lúc tải từng phần các iframe ngoài màn hình!

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 hiển thị cho người dùng dưới dạng hình ảnh hoặc iframe tải từng phần, 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 tải ngay khi trang được in. Hãy xem vấn đề #875403 để biết thông tin 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 và thuộc hệ số cao hơn trong 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 chúng vượt qua bài kiểm tra Trì hoãn hình ảnh ngoài màn hình.

Tải từng phần hình ảnh để cải thiện hiệu suất

Tính năng hỗ trợ trình duyệt cho hình ảnh tải từng phần có thể giúp bạn cải thiện hiệu suất trang dễ dàng hơn đáng kể.

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!