Lazy loading là một kỹ thuật tải dữ liệu một cách linh hoạt, chỉ khi cần thiết. Bạn có thể thấy ví dụ của Lazy loading trên Facebook. Khi bạn vào trang web Facebook, bạn chỉ thấy một số bài đăng đầu tiên. Khi bạn kéo xuống dưới cùng trang, Facebook sẽ tiếp tục tải thêm các bài đăng mới để bạn xem. Nhờ Lazy loading, Facebook có thể giảm thiểu lượng dữ liệu tải về và tăng tốc độ hiển thị trang.
Hôm nay, blog muốn thảo luận về việc triển khai kỹ thuật Lazy Loading cho một thành phần cụ thể, đó là hình ảnh.
Lazy Loading là gì?
Lazy loading là một cách làm cho trang web nhanh hơn và tiết kiệm băng thông. Kỹ thuật này chỉ tải những phần tử quan trọng để người dùng có thể nhìn thấy trang web ngay lập tức, còn những phần tử khác sẽ được tải sau khi người dùng cuộn trang hoặc nhấn vào. Nhờ Lazy loading, trang web không phải tải quá nhiều dữ liệu một lần, mà chỉ tải khi cần, giúp tăng trải nghiệm cho người dùng.
Image is critical
Chúng ta hãy xem xét ví dụ sau đây, đó chỉ là một trang HTML đơn giản với một hình ả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ínhloading
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ínhdata-src
hoặcdata-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.