Hỏi - đáp Nơi cung cấp thông tin nghề nghiệp và giải đáp những thắc mắc thường gặp của bạn

Kỹ Thuật Lazy Loading Không Phải Dev Nào Cũng Biết

Bạn có thể dễ dàng nhận ra khi xem trên Facebook. Lần đầu mở trang web Facebook lên bạn sẽ đọc được 1 số lượng ít tin. Khi bạn cuộn đến cuối trang thì Facebook sẽ bắt đầu tải 1 số lượng tin tiếp theo để hiển thị. Đó chính là Lazy loading.

Hôm nay, mình xin chia sẻ về việc áp dụng kỹ thuật lazy loading đối với 1 thành phần nhỏ là Ảnh.

Lazy Loading là gì?

Lazy loading là 1 kĩ thuật tối ưu khi làm web, thay vì tải toàn bộ trang web và render ngay từ đầu, kỹ thuật này cho phép tải ngay các thành phần cần thiết để hiển thị tới người dùng và trì hoãn các tài nguyên còn lại cho đến khi cần.

Image is critical

Chúng ta hãy cùng xem ví dụ sau, chỉ là 1 trang HTML cơ bản với 1 bức ảnh.

Bây giờ, thì mở phần Network Timeline trong Chrome DevTools.

DevTools report sự kiện load (hay onload) được khởi tạo ở 335ms. Như vậy, sự kiện load đã bị block bởi "awesome-photo.jpg".

Bạn có thể tưởng tượng là với ví dụ đơn giản trên thì không ảnh hưởng gì đến trải nghiệm của người dùng cả vì trang web sẽ rất nhanh được hiển thị. Tuy nhiên, nếu trang web có 10, 20, ... 100 ảnh thì sao. Không khó để đoán là thời gian chờ sẽ càng ngày càng lâu. Theo báo cáo của HTTP Archive (tại thời điểm 27/Jul/2020), trung bình 1 trang web trên desktop có dung lượng 1999.9 KB. Trong khi, trung bình 1 trang web trên desktop có dung lượng ảnh là 947.1 KB chiếm khoảng 47,35 %. Chúng ta không thể làm ngơ các vấn đề liên quan đến Ảnh, nó quá quan trọng đối với trải nghiệm của người dùng.

Kỹ thuật lazy loading đối với Ảnh

Cơ bản, khi khai báo 1 thành phần ảnh chúng ta làm như sau:

<img src="awesome-photo.jpg">

Vậy muốn ứng dụng lazy loading cho thành phần này thì chúng ta thêm thuộc tính loading với giá trị lazy:

<img src="awesome-photo.jpg" loading="lazy">

Dưới đây là các giá trị được hỗ trợ cho thuộc loading:

  • auto: Giá trị mặc định phụ thuộc vào hành vi của từng trình duyệt, tương tự với việc không thêm thuộc tính loading vào.
  • lazy: Trì hoãn tải tài nguyên về cho đến khi đạt 1 khoảng cách nào đó từ khung nhìn.
  • eager: Tải tài nguyên ngay lập tức, bất kể vị trí của nó trên trang.

 Theo trang Can I Use thì thuộc tính loading đã được đa số các trình duyệt implement rồi. Bạn có thể yên tâm sử dụng.

Vậy còn đối với các trình duyệt chưa hỗ trợ thì làm sao. Bạn có thể tạo 1 polyfill hoặc dùng thư viện của bên thứ 3 như LazySizes. Thuộc tính loading có thể dùng để phát hiện xem trình duyệt có hỗ trợ tính năng này hay không:

if ('loading' in HTMLImageElement.prototype) {
  // trình duyệt có hỗ trợ
} else {
  // sử dụng polyfill hoặc thư viện của bên thứ 3
}

LazySizes

LazySizes là thư viện có tốc độ cao, tối ưu SEO và tự khởi tạo (self-initializing) cho mục đích lazy load ảnh (bao gồm cả ảnh đáp ứng picture / srcset), iframe, script / widget và nhiều thành phần khác nữa. Nó cũng ưu tiên các tài nguyên dựa trên sự khác biệt về tầm mức quan trọng, trong đó. LazySizes ưu tiên các phần tử nằm trong khung nhìn và gần khung nhìn trình duyệt (near view elements) để tối ưu tốc độ tải nhận thức (perceived performance) nhanh hơn.

  • Bước 1: thêm link đến CDN chứa LazySizes:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.2.0/lazysizes.min.js" async=""></script>

hoặc bạn có thể tải về web server & để link trực tiếp trên server:

<script src="lazysizes.min.js" async=""></script>
  • Bước 2: thêm class lazyload vào ảnh với thuộc tính data-src hoặc data-srcset:
<!-- non-responsive: -->
<img data-src="image.jpg" class="lazyload" />
<!-- responsive example with automatic sizes calculation: -->
<img
    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w" class="lazyload" />

Lưu ý: LazySizes không cần bất kỳ cấu hình bằng JavaScript nào.

Tránh sử dụng lazy loading cho ảnh trong khung nhìn đầu tiên

Bạn chỉ nên thêm lazy loading cho các ảnh ở bên dưới khung hiển thị đầu tiên. Các hình ảnh với thuộc tính eager được tải ngay lập tức bất kể vị trí trên trang. Trong khi các hình ảnh với thuộc tính loading thì trình duyệt cần phải đợi cho đến khi biết được vị trí của hình ảnh trên trang dựa trên IntersectionObserver. Nói chung, bất kỳ hình ảnh nào trong khung nhìn cần được trình duyệt tải ngay 1 cách mặc định. Bạn không cần chỉ định thuộc tính loading=eager cho những trường hợp ả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">

Testing lazy loading

Chúng ta sẽ cùng check xem ảnh có được tải chậm thật không nhé. Mở Chrome DevTools bằng cách nhấn F12 hoặc click chuột phải chọn Inspect Elements sau đó chọn tab Network → Img. Ở lần refresh page đầu tiên bạn sẽ chỉ nhìn thấy 1 số ảnh phía trên được load.

Sau đó khi bạn scroll xuống dưới thì sẽ thấy những ảnh khác ngay lập tức được load theo.

Kết luận

Việc các trình duyệt đã hỗ trợ chính thức (native) lazy loading có thể giúp bạn dễ dàng cải thiện trang web của mình hơn. Nếu bạn nhận thấy bất kỳ behavior nào không bình thường của tính năng lazy loading trên Google Chrome thì bạn có thể thông báo tại đây. Hy vọng bạn sẽ có tư duy sử dụng lazy loading ngay từ khi develop trang web.

Nguồn: codelearn.io