Vài lời của người dịch: Bài viết này chủ yếu dành cho những ai muốn tìm hiểu sâu hơn về lazy load, nó đòi hỏi bạn phải có hiểu biết nhất định về HTML, JavaScript, CSS. Với những ai đơn thuần chỉ muốn áp dụng lazy load lên trang WordPress, có thể tìm hiểu các plugin sẵn có chất lượng như Flying Images, a3 Lazy Load, vân vân. Nhìn chung tôi ủng hộ tính năng lazy load, nhưng như một cách tự phản biện, tôi chủ động tìm hiểu các điểm yếu của nó, chẳng hạn ở đây và ở đây và cả đây nữa.
Bạn đang xem: Lazy loading là gì
Lưu ý: Hiện bạn đã có thể sử dụng lazy load cấp độ trình duyệt (native lazy loading)! Bạn có thể tham khảo link vừa dẫn để biết cách sử dụng thuộc tính loading và tận dụng thư viện của bên thứ ba đóng vai trò như một dự phòng (fallback) cho các trình duyệt vẫn chưa hỗ trợ thuộc tính này.
Thành phần ảnh và video trên website thường chiếm một lượng dữ liệu tải về lớn. Không may là các bên liên quan đến dự án có thể không thích cắt giảm bất cứ tài nguyên media (đa phương tiện) nào từ các ứng dụng đã có của họ. Tình huống bế tắc như vậy gây bực bội, đặc biệt khi tất cả mọi người đều muốn cải thiện hiệu suất và tốc độ, nhưng lại không đồng thuận về cách để đạt được điều đó. May thay, lazy load là giải pháp giúp bạn có được dung lượng trang cần phải tải lần đầu (initial page payload)* thấp và thời gian tải lần đầu ngắn hơn, nhưng không bắt bạn phải cắt bỏ nội dung.
(*) initial page payload: dung lượng trang tải lần đầu. Từ khóa ở đây là initial/lần đầu. Các trang không lazy load thì trang sẽ tải một lượt tất cả các tài nguyên trên trang, còn với trang áp dụng lazy load, nội dung của trang sẽ không tải một lượt tất cả, mà nó sẽ được chia làm nhiều lần, các nội dung lazy load sẽ tải sau khi đạt điều kiện kích hoạt (trigger).
Lazy load là gì?
Lazy load là kỹ thuật thực hiện trì hoãn (defer) tải các tài nguyên không quan trọng (non-critical resoureces) vào thời điểm tải trang (page load time). Thay vì tải ngay lập tức, các tài nguyên không quan trọng này chỉ tải vào thời điểm cần thiết (moment of need). Khi đề cập đến ảnh, thì “không quan trọng” thường đồng nghĩa với “ngoài màn hình / off-screen”. Nếu bạn sử dụng Lighthouse và kiểm tra một số cơ hội cải thiện, bạn có thể thấy một vài hướng dẫn trong địa hạt này ở dạng kiểm tra các ảnh ngoài màn hình:
Hình 2. Một ví dụ về lazy load ảnh trong thực tế. Một ảnh chiếm chỗ được tải ở bên trái vào thời điểm tải trang, và khi được cuộn đến viewport, ảnh cuối cùng (ảnh thực) được tải vào thời điểm phù hợp để thay thế ảnh chiếm chỗ.
Nếu bạn không quen thuộc với lazy load, bạn có thể tự hỏi lợi ích của kỹ thuật này là gì. Hãy đọc tiếp để biết nhé!
Tại sao lại cần lazy load ảnh hoặc video mà không tải chúng luôn cho rồi?
Bởi vì có khả năng là bạn đang tải về các thành phần trên trang mà người dùng có thể không bao giờ nhìn đến. Điều này là vấn đề vì hai lý do sau:
Nó là sự lãng phí dữ liệu. Trên các kiểu kết nối băng thông không giới hạn (unmetered), điều tồi tệ nhất có thể vẫn chưa xảy ra đâu (dù bạn có thể sử dụng lượng băng thông quý giá này để ưu tiên tải các tài nguyên khác mà người dùng thực sự sẽ nhìn thấy). Trên các gói giới hạn dữ liệu, tải các thành phần người dùng không bao giờ nhìn đến có thể làm lãng phí tiền của họ.
Khi chúng ta lazy load ảnh và video, chúng ta làm giảm thời gian tải cần thiết để tải trang lúc ban đầu (initial page) thông qua giảm dung lượng tải trang lúc ban đầu, cũng như giảm sử dụng tài nguyên hệ thống, tất cả đều ảnh hưởng tích cực đến hiệu suất. Trong hướng dẫn này, chúng ta sẽ bàn về một số kỹ thuật và các chỉ dẫn để thực hiện lazy load ảnh và video cũng như một danh sách ngắn các thư viện phổ biến thường được dùng.
Lazy load ảnh
Cơ chế lazy load ảnh đơn giản về mặt lý thuyết, nhưng đi vào chi tiết thì lại khá khó nhằn (finicky). Thêm vào đó có một số trường hợp riêng biệt có thể có cả lợi ích từ lazy load. Nào, chúng ta cùng bắt đầu tìm hiểu cách lazy load các ảnh nội tuyến (inline) trong HTML.
Xem thêm: Bộ luật dân sự là gì ? phân biệt luật dân sự với các ngành luật khác ?
Ảnh nội tuyến
Các ứng cử viên phổ biến nhất để lazy load là các ảnh sử dụng phần tử
Có ba thành phần liên quan của mã đánh dấu này mà chúng ta cần tập trung vào:
Thuộc tính class, sẽ được JavaScript dùng để lựa chọn phần tử (element).Thuộc tính src, đóng vai trò ảnh giữ chỗ, và sẽ xuất hiện khi trang tải lần đầu tiên. Ảnh giữ chỗ này tất nhiên có kích cỡ rất nhỏ.Các thuộc tính data-src và data-srcset là nơi chứa URL ảnh thực mà bạn muốn hiển thị cho người dùng khi phần từ nằm trong khung nhìn trình duyệt.
Giờ chúng ta sẽ học cách sử dụng intersection observer trong JavaScript để lazy load ảnh bằng mã đánh dẫu mẫu dưới đây:
document.addEventListener(“DOMContentLoaded”, function() { var lazyImages = .slice.call(document.querySelectorAll(“img.lazy”)); if (“IntersectionObserver” in window) { let lazyImageObserver = new IntersectionObserver(function(entries, observer) { entries.forEach(function(entry) { if (entry.isIntersecting) { let lazyImage = entry.target; lazyImage.src = lazyImage.dataset.src; lazyImage.srcset = lazyImage.dataset.srcset; lazyImage.classList.remove(“lazy”); lazyImageObserver.unobserve(lazyImage); } }); }); lazyImages.forEach(function(lazyImage) { lazyImageObserver.observe(lazyImage); }); } else { // Bạn có thể thêm các dự phòng ở phần này để tăng tính tương thích }});Dựa vào sự kiện DOMContentLoaded của tài liệu, đoạn mã trên truy vấn DOM để lấy tất cả các phần tử có class là lazy. Nếu intersection observer khả dụng, chúng ta sẽ tạo một observer mới để chạy callback khi phần tử img.lazy đi vào khung nhìn trình duyệt. Kiểm tra ví dụ trên CodePen để thấy cách đoạn mã này hoạt động trong thực tế.
Ví dụ tôi thực hiện dựa vào mã mẫu ở trên: https://code.thienmaonline.vn/hand-code-lazyload1.html
Lưu ý: Đoạn mã ở trên sử dụng phương thức intersection observer có tên isIntersecting, đây là phương thức không có trong triển khai của intersection observer của Edge phiên bản 15. Do đó, đoạn mã lazy load ở trên (và các đoạn mã tương tự khác) sẽ lỗi trên Edge.
Sử dụng trình xử lý sự kiện (cách có tính tương thích cao nhất)
Dù bạn phải sử dụng intersection observer để triển khai lazy load, thì khả năng tương thích với trình duyệt của ứng dụng vẫn là điều quan trọng. Bạn có thể triển khai dự phòng cho intersection observer (và đây là cách dễ nhất), ngoài ra bạn cũng có thể dự phòng cho đoạn mã bằng cách sử dụng các trình xử lý sự kiện như là scroll, resize, và có thể là orientationchange kèm sự phối hợp với getBoundingClientRect để xác định xem liệu một phần tử có ở trong khung nhìn trình duyệt hay không.
Giả sử với cùng mẫu đánh dấu từ trước, đoạn mã JavaScript sau đây sẽ cung cấp tính năng lazy load:
document.addEventListener(“DOMContentLoaded”, function() { let lazyImages = .slice.call(document.querySelectorAll(“img.lazy”)); let active = false; const lazyLoad = function() { if (active === false) { active = true; setTimeout(function() { lazyImages.forEach(function(lazyImage) { if ((lazyImage.getBoundingClientRect().top = 0) && getComputedStyle(lazyImage).display !== “none”) { lazyImage.src = lazyImage.dataset.src; lazyImage.srcset = lazyImage.dataset.srcset; lazyImage.classList.remove(“lazy”); lazyImages = lazyImages.filter(function(image) { return image !== lazyImage; }); if (lazyImages.length === 0) { document.removeEventListener(“scroll”, lazyLoad); window.removeEventListener(“resize”, lazyLoad); window.removeEventListener(“orientationchange”, lazyLoad); } } }); active = false; }, 200); } }; document.addEventListener(“scroll”, lazyLoad); window.addEventListener(“resize”, lazyLoad); window.addEventListener(“orientationchange”, lazyLoad);});Đoạn mã trên sử dụng getBoundingClientRect trong trình xử lý sự kiện scroll để kiểm tra xem có bất kỳ phần tử img.lazy nào nằm trong khung nhìn trình duyệt hay không. setTimeout được gọi để trì hoãn xử lý, và biến active chứa thông tin trạng thái quá trình xử lý- cái được sử dụng để điều chỉnh các lời gọi liên quan đến chức năng. Vì ảnh được lazy load, chúng sẽ bị loại bỏ khỏi mảng phần tử. Khi mảng phần tử đạt đến length là 0, đoạn mã của trình xử lý sự kiện scroll bị loại bỏ. Bạn có thể xem ví dụ này trên CodePen để thấy đoạn mã trong thực tế.
Ví dụ về đoạn mã sử dụng trình xử lý sự kiện: https://code.thienmaonline.vn/hand-code-lazyload2.html
Trong khi đoạn mã này hoạt động được trên hầu hết các trình duyệt, nó có khả năng có các vấn đề về hiệu suất khi lời gọi setTimeout lặp lại có thể gây lãng phí, ngay cả khi đoạn mã bên trong chúng đã được điều chỉnh. Trong ví dụ này, một kiểm tra được chạy lặp đi lặp lại với tần suất 200 mili giây khi tài liệu được cuộn hoặc kích cỡ cửa sổ thay đổi bất kể chuyện có ảnh trong viewport hay không. Thêm vào đó, công việc theo dõi để biết còn có bao nhiêu phần tử còn lại cần lazy load thật tẻ nhạt, và việc bỏ trình xử lý sự kiện scroll được để dành lại cho nhà lập trình.
Kết luận đơn giản: Sử dụng intersection observer bất cứ khi nào có thể, và thực hiện dự phòng bằng trình xử lý sự kiện nếu tính tương thích rộng nhất là yêu cầu quan trọng của ứng dụng.
Xem thêm: Obscure Là Gì – Nghĩa Của Từ Obscure
Ảnh trong CSS
Dù thẻ là cách sử dụng ảnh phổ biến nhất trên các trang web, thì ảnh cũng có thể được gọi (invoked) qua thuộc tính CSS là background-image (và các thuộc tính khác nữa). Không giống với phần tử sẽ được tải bất kể nó có đi vào khung nhìn trình duyệt hay không, hành vi tải ảnh trong CSS được thực hiện với nhiều suy đoán, tính toán (speculation) hơn. Khi tài liệu và mô hình đối tượng CSS (the document and CSS object models) cũng như cây kết xuất (render tree) được xây dựng, trình duyệt sẽ kiểm tra cách CSS được áp dụng vào tài liệu trước khi yêu cầu các tài nguyên bên ngoài. Nếu trình duyệt phát hiện một quy tắc CSS liên quan đến tài nguyên bên ngoài không được áp dụng vào tài liệu như cách nó đang được xây dựng thì trình duyệt sẽ không gửi yêu cầu đến tài nguyên đó.
Hành vi tính toán này có thể được sử dụng để trì hoãn các ảnh trong CSS bằng cách sử dụng JavaScript để phát hiện khi một phần tử nằm trong khung nhìn trình duyệt, và sau đó áp một class vào phần tử mà class đó được áp dụng style gọi ảnh nền (background image). Cái này sẽ giúp ảnh được tải vào thời điểm cần thiết thay vì tải ngay lúc ban đầu. Ví dụ, hãy lấy một phần tử có chứa một ảnh background lớn ở vị trí thu hút:
Chuyên mục: Hỏi Đáp