Group
Trình duyệt Chrome chính thức hỗ trợ lazy-loading cho ảnh và iframe ở cấp độ trình duyệt!
Bắt đầu từ Chrome 76, bạn có thể sử dụng thuộc tính loading để lazy load các tài nguyên mà không cần viết riêng mã lazy-loading hoặc sử dụng riêng thư viện JavaScript (chẳng hạn như lazysizes). Chúng ta sẽ đi vào chi tiết ngay sau đây.
P/S: native trong cụm từ “native lazy-loading” có thể được dịch sát nghĩa là “tải lười kiểu bản địa” hoặc “lazy-loading bản địa”, tuy nhiên tôi (người dịch) thấy giữ nguyên từ gốc tiếng Anh hay hơn, hoặc nếu có dịch sẽ dùng từ “lazy-loading cấp trình duyệt” cho dễ hiểu.
Theo HTTPArchive, ảnh là thành phần được yêu cầu nhiều nhất trên hầu hết website và thường chiếm nhiều băng thông hơn bất kỳ tài nguyên nào. Ở phân vị 90(*), các website gửi 4,7 MB ảnh trên máy bàn và di động.
(*): phân vị thứ 90 (90th percentile), theo cách hiểu thông thường là những trang web có dung lượng ảnh lớn hơn 90% các website khác, nói cách khác top 10% các website có nhiều ảnh nhất chứa ít nhất 4,7 MB ảnh.
Nhúng iframe cũng sử dụng rất nhiều dữ liệu và có thể ảnh hưởng tiêu cực đến hiệu suất của trang (page performance). Nếu chúng ta chỉ tải các ảnh, iframe không quan trọng (non-critical), nằm trong màn hình thứ hai trở đi (below-the-fold) khi người dùng cần xem chúng thì sẽ giúp cải thiện thời gian tải trang (page load times), tối thiểu hóa băng thông (bandwidth), và giảm sử dụng bộ nhớ.
Hiện tại có hai cách để trì hoãn tải ảnh và iframe không thuộc màn hình đầu tiên (off-screen):
Cả hai tùy chọn này có thể cho phép lập trình viên bao gồm hàm lazy-loading vào website, và nhiều lập trình viên xây dựng thư viện của bên thứ ba để đưa ra các abstraction thậm chí còn dễ sử dụng hơn. Nhưng với lazy-loading được hỗ trợ trực tiếp bởi trình duyệt, bạn không cần đến các thư viện bên ngoài (external library) nữa. Native lazy loading cũng đảm bảo việc trì hoãn tải ảnh và iframes vẫn hoạt động bình thường ngay cả khi JavaScript bị vô hiệu hóa trên trình duyệt của người dùng (còn gọi là máy khách/client).
P/S: Rất hiếm khi trình duyệt bị vô hiệu hóa JavaScript, vì các website hiện đại, nhiều chức năng thì JavaScript là một thành phần cốt lõi, nhưng nếu nó bị vô hiệu hóa, mà trang của bạn không triển khai dự phòng bằng thẻ <noscript> thì lazy load sẽ bị gặp lỗi không hiển thị ảnh. Bạn có thể thử vô hiệu hóa JS trên Chrome bằng cách vào copy đường dẫn sau vào thanh địa chỉ:
chrome://settings/content/javascript
Rồi nhấn button vô hiệu hóa.
Ở thời điểm hiện tại, Chrome đã hỗ trợ tải ảnh ở các cấp độ ưu tiên khác nhau phụ thuộc vào vị trí của nó tương quan với viewport (khung nhìn) của thiết bị. Ảnh ở bên dưới viewport được tải với mức ưu tiên thấp hơn (lower priority), nhưng chúng sẽ vẫn được tìm nạp (fetched) để tải về nhanh nhất có thể (as soon as possible).
Trong Chrome 76, bạn có thể sử dụng thuộc tính loading để trì hoãn tải hoàn toàn các ảnh và iframes không thuộc màn hình đầu tiên (những khu vực mà phải cuộn chuột mới tiếp cận được), mã trông giống như thế này:
<img src="image.png" loading="lazy" alt="…" width="200" height="200">
<iframe src="https://example.com" loading="lazy"></iframe>
Dưới đây là các giá trị hỗ trợ cho thuộc tính loading:
P/S: các từ mà người dịch thêm vào là tự động, lười, hăng hái để bạn dễ nhớ và dễ hiểu hơn thôi.
Tính năng này sẽ tiếp tục được cập nhật cho đến khi nó được phát hành trong phiên bản ổn định (Chrome 76 là phiên bản đầu tiên). Nhưng bạn có thể thử nó bằng cách bật flags dưới đây trong Chrome:
chrome://flags/#enable-lazy-image-loading
chrome://flags/#enable-lazy-frame-loading
Tất cả các ảnh và iframe nằm trong màn hình đầu tiên (above the fold) — tức là những thứ xuất hiện ngay trong khung nhìn trình duyệt mà không cần cuộn chuột — sẽ được tải bình thường. Nhưng các ảnh và iframes nằm xa bên dưới viewport của thiết bị chỉ được tìm nạp khi người dùng cuộn chuột gần đến chúng (when user scrolls near them).
Ngưỡng khoảng cách là không cố định (not fixed) và tùy thuộc vào một số yếu tố sau:
Bạn có thể tìm thấy các giá trị mặc định cho các kiểu kết nối khác nhau trên nguồn dữ liệu Chromium. Các con số này, và thậm chí là cách tiếp cận chỉ tìm nạp khi đạt đến khoảng cách nhất định từ viewport có thể thay đổi trong tương lai gần khi nhóm phát triển trình duyệt Chrome cải thiện heuristics (*) để xác định được khi nào nên bắt đầu tải.
(*): Kiểu quy tắc/thuật giải được phát triển dựa trên kinh nghiệm, thường là tối ưu trong phần lớn trường hợp nhưng không phải trong mọi trường hợp và có thể không phải là biện pháp tốt nhất có thể tồn tại. Ưu điểm của nó là cho chất lượng sản phẩm đủ tốt nhưng không mất nhiều thời gian phát triển.
Tôi (người dịch) sẽ cung cấp luôn thông tin về ngưỡng khoảng cách tải ở thời điểm hiện tại (cuối năm 2019):
// // Lazy image loading distance-from-viewport thresholds for different effective connection types. // { name: "lazyImageLoadingDistanceThresholdPxUnknown", initial: 5000, type: "int", }, { name: "lazyImageLoadingDistanceThresholdPxOffline", initial: 8000, type: "int", }, { name: "lazyImageLoadingDistanceThresholdPxSlow2G", initial: 8000, type: "int", }, { name: "lazyImageLoadingDistanceThresholdPx2G", initial: 6000, type: "int", }, { name: "lazyImageLoadingDistanceThresholdPx3G", initial: 4000, type: "int", }, { name: "lazyImageLoadingDistanceThresholdPx4G", initial: 3000, type: "int", },
Từ đoạn mã trên ta nhận thấy rằng trình duyệt Chrome sẽ:
Bạn có thể quan sát thấy quy luật là trên mạng càng nhanh, ngưỡng khoảng cách tải sẽ càng thấp.
Lưu ý: Trong Chrome 77, bạn có thể trải nghiệm các ngưỡng khác nhau bằng cách điều chỉnh mạng trong DevTools (công cụ cho nhà phát triển được tích hợp sẵn trong Chrome), bạn sẽ cần ghi đè ảnh hưởng của kiểu kết nối trong trình duyệt bằng cách sử dụng flag:
chrome://flags/#force-effective-connection-type
Để ngăn các nội dung xung quanh không reflowing(**) khi ảnh lazy-load tải, cần đảm bảo thêm thuộc tính height và width vào thành phần <img> hoặc chỉ định giá trị cụ thể, trực tiếp trong style nội tuyến (inline style):
<img src="..." loading="lazy" width="200" height="200">
<img src="..." loading="lazy" style="height:200px; width:200px;">
(**): reflowing là hiện tượng trình duyệt phải tính toán lại vị trí và bố cục của các thành phần trong tài liệu HTML, đây là hành vi sẽ khiến người dùng bị cản trở nên cần phải tránh. Bạn có thể tham khảo thêm thông tin về nó ở liên kết này.
Các ảnh sẽ vẫn được lazy-load nếu kích cỡ (dài, rộng) không được chỉ định, nhưng việc thông báo kích cỡ cho chúng sẽ giúp làm giảm khả năng trình duyệt bị reflow.
Hỗ trợ cho thuộc tính intrinsicsize vẫn đang được tiếp tục thực hiện, vì thế các ảnh sẽ vẫn được lazy-load chính xác nếu intrinsicsize được chỉ định kèm với một trong hai kích cỡ (width hoặc height).
<img src="…" alt="…" loading="lazy" intrinsicsize="250x200" width="450">
<!-- lazy-loaded -->
P/S: Bạn có thể xem ví dụ demo về cách thuộc tính loading làm việc với 100 bức ảnh sau (toàn mèo dễ thương).
Thuộc tính loading ảnh hưởng đến iframe khác so với ảnh, phụ thuộc vào việc liệu iframe có ẩn hay không. (Các iframe ẩn thường được sử dụng cho mục đích phân tích hoặc giao tiếp). Chrome sử dụng các đặc điểm sau để xác định liệu một iframe có đang ẩn hay không:
Nếu một iframe thỏa mãn bất kỳ điều kiện nào kể trên, Chrome xem nó là ẩn và không lazy-load nó trong phần lớn trường hợp. Iframe không ẩn sẽ chỉ được tải khi nó nằm trong ngưỡng khoảng cách cho phép tải (đã nói ở trên). Placeholder hiển thị cho iframes lazy-load sẽ vẫn được tìm nạp.
Có một số kế hoạch trong việc thay đổi hành vi lazy-loading mặc định của trình duyệt để tự động tải lười bất cứ ảnh hoặc iframe nào mà phù hợp để trì hoãn nếu chế độ Lite được bật trên Chrome cho Android.
Không, hiện tại nó chỉ được sử dụng với các thẻ <img> mà thôi. Nói cách khác các ảnh background vẫn tải bình thường.
Chỉ các ảnh từ màn hình thứ hai trở đi mới được tải lười (kết hợp với việc nó thỏa mãn tiêu chí về ngưỡng khoảng cách). Tất cả các ảnh nằm trong màn hình đầu tiên, bất kể là nó không quan sát thấy ngay lúc đầu sẽ được tải như bình thường.
Thuộc tính loading không ảnh hưởng gì đến mã lazy-load bạn đang sử dụng trên các tài nguyên, nhưng có vài điểm quan trọng sau cần để ý:
Một trong các lý do quan trọng để tiếp tục sử dụng thư viện của bên thứ ba song song với loading=”lazy” đó là để hỗ trợ (polyfill) cho các trình duyệt hiện chưa có thuộc tính này.
Thuộc tính loading có thể được coi là một cải tiến, cho phép các trình duyệt hỗ trợ nó có thể lazy-load ảnh và iframe. Những trình duyệt chưa hỗ trợ sẽ vẫn tải theo cách cũ như hiện nay. Về mặt hỗ trợ chéo trình duyệt, loading được hỗ trợ trên Chrome 76 và bất kỳ trình duyệt nào dựa trên Chromium 76 (ví dụ như Cốc Cốc). FireFox cũng đang mở thảo luận việc tích hợp thuộc tính này vào.
Một API tương tự đã được đề xuất và sử dụng trong IE và Edge nhưng nó tập trung vào việc hạ thấp mức độ ưu tiên tải xuống của các tài nguyên thay vì trì hoãn tải chúng hoàn toàn. Nó không còn ủng hộ resource hints (gợi ý tài nguyên) nữa.
Bạn có thể sử dụng thư viện của bên thứ ba hoặc các đoạn mã hỗ trợ khác để tải lười các ảnh trên website. Thuộc tính loading có thể được detect (phát hiện) nếu tính năng này được hỗ trợ trong trình duyệt nhờ đoạn mã sau:
if ('loading' in HTMLImageElement.prototype) {
// có hỗ trợ trên trình duyệt này
} else {
// sử dụng thư viện hoặc mã dự phòng
}
Ví dụ, lazysize là thư viện lazy-loading JavaScript phổ biến. Bạn có thể sử dụng đoạn mã dùng ở trên để phát hiện thuộc tính loading có được hỗ trợ trên trình duyệt không, nếu nó không, hãy dự phòng bằng lazysize. Điều đó được thực hiện như sau:
<!-- 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/4.1.8/lazysizes.min.js';
document.body.appendChild(script);
}
</script>
Dưới đây là trang demo cho kiểu tải này. Bạn hãy thử nó trên trình duyệt FireFox hoặc Safari để xem mã dự phòng hoạt động ra sao.
Lưu ý: Thư viện lazysizes cũng cung cấp plugin native loading được sử dụng để native lazy-loading khi có cơ hội nhưng vẫn có dự phỏng bằng chức năng tùy chỉnh của thư viện khi cần thiết.
Tất cả các quảng cáo hiển thị cho người dùng dưới dạng ảnh hoặc iframe sẽ được lazy-load giống như bất kỳ ảnh hoặc iframe nào khác.
Mặc dù chức năng này không có trong Chrome 76, có một open issue để đảm bảo rằng tất cả ảnh và iframe được tải ngay lập tức nếu trang trong chế độ in ấn.
Triển khai lazy-loading ảnh và iframe dưới dạng native của trình duyệt có thể làm nhiệm vụ này trở nên dễ dàng hơn đáng kể cho mục tiêu cải thiện hiệu suất của trang web.
Nếu bạn để ý thấy bất kỳ hành vi bất thường nào với tính năng này trên Chrome hãy báo cho chúng tôi biết.
(Dịch từ bài viết: Native lazy-loading for the web, các tác giả: Houssein Djirdeh, Addy Osmani và Mathias Bynens, trang web: web[.]dev)
Thông tin bổ sung. Hiện tôi biết có 2 plugin cho WordPress hỗ trợ tính năng native lazy-loading là: