Categories Lazy load Lazysizes

Giới thiệu thư viện lazysizes.js để lazy load ảnh (phần 1)

Vài lời của người dịch: Nhờ bài viết về cách lazy load ảnh và video (có nội dung rất căn bản) tôi biết đến công cụ lazysizes.js (của tác giả có nickname aFarkas), nó được khen ngợi nhiều (rất hay được nhắc tên trong các tài liệu hướng dẫn tăng tốc của Google), do đó tôi quyết định đầu tư thời gian tìm hiểu.

Vì bài khá dài nên được chia làm ba phần. Một lần nữa thì bài viết dạng này chỉ dành cho những ai muốn đào sâu về lazy load và có ý muốn triển khai trên các ứng dụng mà bạn sẽ viết sau này.

Nếu đơn thuần chỉ dùng WordPress bạn cứ xài plugin kiểu như flying images hay a3 Lazy Load có lẽ sẽ nhẹ đầu hơn nhiều. Ngoài phần dịch nội dung chính, tôi có đưa thêm các ví dụ vào cho dễ hiểu. OK, giờ chúng ta bắt đầu nhé.


Công cụ này dùng để lazy load ảnh (gồm cả ảnh đáp ứng và thông thường), iframe (cho video) có hiệu suất cao, thân thiện với SEO. Nó xác định bất kỳ thay đổi nào trong khung nhìn trình duyệt (viewport) mà được kích hoạt bởi tương tác của người dùng (user interaction), CSS hoặc JavaScript mà không cần bạn phải can thiệp cấu hình (configuration).

Link chính thức của thư viện nằm ở đây: github.com/aFarkas/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.

Thư viện này cũng có thể là công cụ hàng đầu để bạn tích hợp ảnh đáp ứng (ảnh có khả năng co giãn theo kích cỡ mãn hình / responsive images). Nó có thể tính toán tự động thuộc tính sizes cho ảnh đáp ứng của bạn, lazysizes cũng cho phép bạn chia sẻ các truy vấn media cho thuộc tính media của bạn bằng CSS, giúp tách biệt CSS (layout) khỏi nội dung / cấu trúc (HTML) và nó thực hiện tích hợp các ảnh đáp ứng vào trong bất cứ môi trường nào theo cách thực sự đơn giản. Lazysizes cũng bao gồm một tập hợp các plugin tùy chọn để mở rộng hơn nữa chức năng của nó.


Cách làm

1. Tải mã lazysizes.min.js về và đưa nó vào trong trang web của bạn. Hoặc cài đặt nó thông qua npm: npm install lazysizes –save hoặc bower bower install lazysizes –save

Đoạn mã để đưa vào trang như sau (thường bạn đưa nó vào trong phần <head>, nằm bên dưới CSS và JS khác):

<script src="lazysizes.min.js" async=""></script>

Ngoài việc tải về và tự host, bạn có thể sử dụng CDN:

<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.2.0/lazysizes.min.js"></script>

Hoặc:

import 'lazysizes';
// import a plugin
import 'lazysizes/plugins/parent-fit/ls.parent-fit';
// Note: Never import/require the *.min.js files from the npm package.

2. lazysizes không cần bất cứ cấu hình JS nào: Chỉ cần thêm class “lazyload” vào ảnh hoặc iframe của bạn và kết hợp với thuộc tính data-src và/hoặc data-srcset. Một tùy chọn nữa là bạn cũng có thể thêm một thuộc tính src với ảnh giữ chỗ chất lượng thấp / low quality image placeholder (đóng vai trò giữ chỗ cho bức ảnh gốc cần tải lười và chủ yếu để quá trình lazy load diễn ra mượt mà hơn):

<!-- không phải ảnh đáp ứng: -->
<img data-src="image.jpg" class="lazyload" />

Bạn có thể xem ví dụ về tải lười ảnh không đáp ứng tại đường dẫn này: https://static.kiencang.net/2020/lazysizes-demo1.html

Để kiểm tra hiệu ứng tải lười, trên trình duyệt Chrome (desktop) bạn làm như sau:

  • Nhấn tổ hợp phím Ctrl + Shift + I
  • Chuyển sang tab Network, chọn Disabale cache (vô hiệu hóa cache trình duyệt để mỗi lần bạn reload, nó sẽ tải lại ảnh thay vì lấy ảnh từ cache, có như vậy mới mô phỏng / giả lập được chính xác hành vi của người dùng lần đầu vào trang của bạn)
  • Ở ngay bên dưới chọn tab Img để chỉ quan sát hành vi tải ảnh về
Kiểm tra lazy load trên Chrome

Ở bên tay trái bạn chọn thiết bị di động muốn kiểm tra, trong ví dụ này tôi chọn iPhone 6/7/8 plus.

chọn thiết bị muốn kiểm tra

Tiếp theo chọn kích cỡ 100% cho dễ quan sát, nếu màn hình máy tính của bạn to bạn có thể để to hơn (125%, 150%):

chọn kích cỡ

Cuối cùng bạn chọn tốc độ kết nối/điều kiện thiết bị:

tốc độ kết nối, điều kiện phần cứng

Từ trên xuống dưới nó sẽ cho tốc độ kết nối, hiển thị lazy load từ nhanh đến chậm (không tính Offline). Nếu trên đường truyền tốc độ cao, phần cứng tốt lazy load sẽ diễn ra rất êm và mượt, bạn thậm chí không nhìn thấy ảnh tải (điều này tốt hơn cho trải nghiệm người dùng). Nhưng trên đường truyền chậm hoặc/và phần cứng yếu ảnh sẽ tải chậm hơn và bạn sẽ nhận ra. Để dễ dàng quan sát, bạn có thể chọn Mid-tier mobile (ý chỉ dòng điện thoại cấp trung). Trong đoạn mã nhúng vừa rồi tôi cho thêm vài bức ảnh có dung lượng lớn (500 KB – 1 MB) ở cuối để ngay cả khi bạn chọn Online (có tốc độ cao nhất) bạn sẽ vẫn nhận ra hiện tượng lazy load.

Sau khi thiết lập xong, bạn tải lại trang, bạn sẽ thấy trang chỉ tải trước 13 bức ảnh (trên tổng số 31 bức):

tải lúc ban đầu chỉ một số bức ảnh
Bạn cũng cũng thấy lượng dữ liệu tải về chỉ khoảng 1 MB.

Tiếp đó bạn cuộn chuột xuống bên dưới trong màn hình giả lập, bạn sẽ thấy trình duyệt tải dần các ảnh còn lại về tương ứng với quá trình cuộn chuột:

tải ảnh còn lại về
Trình duyệt tải đủ 31 ảnh về, với hơn 5,8 MB dữ liệu

Để so sánh giữa ảnh theo phương thức tải lười và tải thông thường, tôi có tạo một trang cũng bao gồm các ảnh trên nhưng tải theo cách thông thường, không có lazy load: https://static.kiencang.net/2020/tai-anh-thong-thuong-demo1.html

Tiếp theo chúng ta sẽ làm quen với mã sử dụng ảnh đáp ứng với việc tính toán kích cỡ tự động:

<!-- ảnh đáp ứng với việc tính toán kích cỡ tự động: -->
<img
    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w" class="lazyload" />

Trang mẫu demo đoạn mã trên ở link này: https://static.kiencang.net/2020/lazysizes-auto-resize-anh.html

Tiếp theo là đoạn mã lazy load cho video:

<!-- ví dụ về iframe -->
<iframe frameborder="0"
    class="lazyload"
    allowfullscreen=""
    data-src="//www.youtube.com/embed/ZfV-aYdU4uE">
</iframe>

Còn đây là trang mẫu cho iframe YouTube: https://static.kiencang.net/2020/lazysizes-iframe.html

Nếu bạn dùng WordPress, plugin rất tốt để tải lười video là: WP YouTube Lyte (cũng là tác giả phát triển plugin Autoptimize – rất nổi tiếng và chất lượng về mảng tối ưu tốc độ)


Hỗ trợ ảnh đáp ứng (picture và/hoặc srcset)

Lazysizes được xây dựng dựa trên các tiêu chuẩn về ảnh đáp ứng và cho phép bạn mở rộng nó với các chức năng bổ sung. Để có thể có được hỗ trợ ảnh đáp ứng trên tất cả các trình duyệt (full cross browser), bạn phải thực hiện vá víu (polyfill) đầy đủ với các công cụ như picturefill hoặc sử dụng tiện ích siêu nhẹ respimg polyfill plugin hoặc responsive image on demand plugin. Ngoài ra bạn có thể định nghĩa một dự phòng (fallback) theo cách đơn giản cho src thông qua thuộc tính data-src. Nếu bạn muốn tìm hiểu thêm về cú pháp (syntax) của ảnh đáp ứng, hãy thêm khảo bài viết sau đây: “Mổ sẻ sâu về ảnh đáp ứng“.


Tại sao lazysizes được đánh giá rất cao

lazysizes khác biệt so với các công cụ tải lười ảnh khác:

  1. Nhận diện bất cứ thay đổi nào về khả năng hiển thị trong hiện tại và tương lai của các phần tử lazyload trong bất kỳ môi trường web nào theo cách tự động: Đoạn mã hoạt động phổ cập, tự khởi tạo, tự cấu hình, tự hủy các thành phần và nhận diện bất kỳ thay đổi nào về khả năng hiển thị của bất kỳ phần tử ảnh/iframe trong hiện tại và tương lai một cách tự động, không thành vấn đề là liệu nó có được hiển thị thông qua tương tác của người dùng, một hoạt ảnh CSS được kích hoạt thông qua :hover hoặc thông qua bất kỳ kiểu hành vi JS nào (băng chuyền, slider, cuộn chuột vô tận / infinite scroll, masonry, isotope/filtering/sorting, AJAX, SPAs…). Nó cũng làm việc tự động khi kết hợp với bất kỳ thư viện JS-/CSS-/Frontend- nào (ví dụ jQuery mobile, Bootstrap, Backbone, Angular, React, Ember, bạn có thể xem thêm các extension cho attrchange/re-initialization).
  2. Hướng đến tương lai (future-proof / không lỗi thời): lazysizes trực tiếp hỗ trợ các tiêu chuẩn về ảnh đáp ứng (picturesrcset)
  3. Chia tách các mối quan tâm: Để hỗ trợ ảnh đáp ứng, nó bổ sung thêm tính toán sizes tự động cũng như alias name cho tính năng truy vấn media. Cũng không cần thực hiện thay đổi JS nếu bạn thêm khối có thể cuộn bằng CSS (overflow: auto) hoặc tạo một mega menu chứa các ảnh.
  4. Hiệu suất: nó dựa trên các mã thực hành tốt nhất, có hiệu suất cao (runtime network) để hoạt động nhẹ nhàng ở tốc độ 60 fps và có thể sử dụng với hàng trăm ảnh/iframe trên các trang hoặc ứng dụng web nặng JS và CSS.
  5. Khả năng mở rộng: Nó cung cấp các hook JS và CSS để mở rộng lazysizes với bất kỳ kiểu lazy load nào, khởi tạo lazy, trong view callback hoặc hiệu ứng (xem thêm các plugin/mã sẵn có bên dưới)
  6. Prefetch thông minh/Ưu tiên tài nguyên thông minh: lazysizes prefetch/preload các phần tử ở gần khung nhìn trình duyệt để cải thiện trải nghiệm người dùng, nhưng chỉ khi trình duyệt ở trong thời gian nghỉ (xem thêm các tùy chọn expand, expFactorloadMode / xem phần 2 bài giới thiệu về lazysizes). Đây là cách giúp lazy load nhanh hơn nhờ việc preload trước các phần tử cần lazy trước khi nó đi vào khung nhìn trình duyệt.
  7. Nhẹ nhàng, nhưng là giải pháp hoàn chỉnh: lazysizes cân bằng hợp lý giữa độ dài mã và tốc độ cũng như đưa ra giải pháp tin cậy.
  8. Cải thiện SEO: lazysizes không ẩn ảnh/các phần tử khác khỏi tầm mắt của Google. Không thành vấn đề là bạn đang sử dụng mẫu mã đánh dấu nào. Google không thể cuộn chuột/tương tác với trang web của bạn. lazysizes nhận diện tác nhân người dùng (user agent) có khả năng cuộn chuột hay là không, và nếu không, lazysizes sẽ tự động hiển thị tất cả các ảnh chứ không lazy load nó (ý là với user agent là bọ tìm kiếm như của Google, tính năng lazy load sẽ bị loại bỏ để máy tìm kiếm nhìn được ảnh ngay, qua đó không làm ảnh hưởng đến SEO của bạn).

Tìm hiểu thêm về API

lazysizes đi kèm với mã đánh dấu và JS API đơn giản. Thông thường bạn sẽ chỉ cần sử dụng mã đánh dấu API.

Mã đánh dấu API

Thêm class lazyload vào tất cả các phần tử imgiframe, những cái mà bạn muốn lazy load. Thay vì sử dụng thuộc tính src hoặc srcset hãy sử dụng thuộc tính data-src hoặc data-srcset:

<img data-src="image.jpg" class="lazyload" />
<!-- ảnh tối ưu retina: -->
<img data-srcset="responsive-image1.jpg 1x, responsive-image2.jpg 2x" class="lazyload" />

Tự động thiết lập thuộc tính sizes

lazysizes hỗ trợ thiết lập thuộc tính sizes tự động, tương ứng với kích cỡ hiện tại của hình ảnh – bạn chỉ cần thiết lập giá trị data-sizes thành auto.

<img
	data-sizes="auto"
	data-srcset="responsive-image1.jpg 300w,
	responsive-image2.jpg 600w,
	responsive-image3.jpg 900w"
        class="lazyload" />

Quan trọng: Cách tính toán sizes: Việc tính toán tự động kích cỡ (sizes) được sử dụng để hiển thị chiều rộng của ảnh. Điều này có nghĩa là chiều rộng của ảnh được tính toán (ít nhất là xấp xỉ) trước khi bản thân ảnh đó được tải (Điều này có nghĩa là bạn có thể không cần sử dụng width: auto). Thông thường quy tắc CSS chung sau đây có thể hữu ích: img[data-sizes=”auto”] { display: block; width: 100%; } (xem thêm phần chỉ định kích cỡ ảnh/iframe với các khuyến nghị về định nghĩa tỷ lệ khung hình, cũng trong bài viết này). Nếu nó có giá trị dưới 40 (có thể chỉnh giá trị này thông qua tùy chọn minSize), lazysizes đi qua cây DOM cho đến khi nó tìm được phần từ cha mà có giá trị hơn 40 và sử dụng con số này.

Tính năng tự động tính toán chiều rộng của lazysizes có thể được điều chỉnh bằng cách sử dụng sự kiện lazybeforesizes. Ngoài ra, plugin parent fit có thể được dùng để định kích cỡ ảnh cho khớp với khối cha hoặc bao chứa, và là giải pháp duy nhất khi chiều cao của ảnh cũng cần tính đến khi cần đưa ảnh vào khít khớp với phần bao chứa của nó (điều này cũng bao gồm việc sử dụng object-fit).

Tính năng data-sizes=”auto” chỉ có ý nghĩa nếu bạn sử dụng thuộc tính data-srcset đi kèm với các mô tả về chiều rộng width để hình ảnh phù hợp nhất có thể được chọn (Nó không có ý nghĩa nếu bạn sử dụng mô tả x hoặc chỉ dùng src).


Các mẫu mã đánh dấu được khuyến khích hoặc có thể thực hiện

lazysizes cho phép bạn viết vô số các mẫu mã đánh dấu khác nhau. Bạn có thể tìm mẫu đánh dấu phù hợp nhất cho bản thân hoặc chọn tùy ý một cái bằng các đoạn mã tham khảo dưới đây (Tất cả các mẫu sau cũng có thể sử dụng theo hướng nghệ thuật bằng cách sử dụng phần tử picture.)

Mẫu đơn giản

Thêm class lazyload và đơn giản bỏ qua thuộc tính src hoặc thêm dữ liệu uri như một dự phòng (fallback) cho src.

<!--  ví dụ về ảnh đáp ứng -->
<img
 class="lazyload"
 data-srcset="image.jpg 1x, image2.jpg 2x"
 alt="ảnh của tôi" />
<!--  ví dụ về tối ưu cho retina -->
<img class="lazyload"
 data-srcset="progressive-image.jpg 1x, progressive-image2.jpg 2x"
 alt="ảnh của tôi" />
<!-- hoặc ảnh không đáp ứng: -->
<img
 data-src="image.jpg"
 class="lazyload" />

Lưu ý: trong trường hợp bạn sử dụng cả srcset/data-srcset hoặc picture, chúng tôi khuyên bạn nên mở rộng mẫu này với data-src (xem mẫu kế tiếp: Kết hợp data-srcset với data-src) hoặc với thuộc tính src phù hợp (xem: “mẫu hiện đại” hoặc “LQIP”).

Kết hợp data-srcset với data-src

Trong trường hợp bạn muốn sử dụng ảnh đáp ứng cho các trình duyệt hỗ trợ, nhưng không muốn bao gồm các mã vá víu (polyfill) thêm, bạn chỉ cần đơn giản kết hợp data-srcset với một thuộc tính data-src.

<!-- ví dụ về ảnh đáp ứng: -->
<img
    data-sizes="auto"
    data-src="image3.jpg"
    data-srcset="image3.jpg 600w,
     image1.jpg 220w,
     image2.jpg 300w,
     image3.jpg 600w,
     image4.jpg 900w"
 class="lazyload" />

Lưu ý: Do trong thực tế data-src cũng sẽ được lấy bởi “Read_Later” của các ứng dụng hoặc các công cụ khác (ví dụ Pin trong nút bấm), mẫu này vẫn có ý nghĩa nếu bạn vẫn dùng polyfill. Trong trường hợp bạn không sử dụng polyfill, khuyến cáo là ứng viên hình ảnh đầu tiên cần phải khớp với dự phòng src.

Ảnh giữ chỗ kiểu LQIP/mờ và kỹ thuật ảnh mờ hiện dần thành ảnh rõ (blur up)

Nếu bạn sử dụng mã mẫu kiểu LQIP (Low Quality Image Placeholder / Ảnh giữ chỗ chất lượng thấp), bạn chỉ cần thêm ảnh chất lượng thấp đó vào src:

<!-- ví dụ về ảnh đáp ứng: -->
<img
    data-sizes="auto"
    src="lqip-src.jpg"
    data-srcset="lqip-src.jpg 220w,
    image2.jpg 300w,
    image3.jpg 600w,
    image4.jpg 900w" class="lazyload" />
<!-- hoặc ảnh không đáp ứng: -->
<img src="lqip-src.jpg" data-src="image.jpg" class="lazyload" />

Kỹ thuật LQIP có thể được tăng cường bằng cách kết hợp nó với CSS transitions/animation cho ảnh.

Bạn có thể tham khảo thêm plugin Blur Up lazysizes (khuyến khích).

Đây là cách lazy load ảnh mà tôi rất thích, bởi vì nó sẽ làm cho cơ chế tải lười ảnh diễn ra rất mượt mà. Ảnh sẽ hiện ra theo kiểu tương tự định dạng JPEG Progressive (kể cả ảnh PNG). Cơ chế là trình duyệt sẽ tải ảnh chất lượng thấp của bức ảnh gốc trước để giữ chỗ (có dung lượng rất nhỏ, thường chỉ từ 1 đến 10% dung lượng của ảnh gốc hoặc đôi khi hơn tùy vào lựa chọn của bạn), sau đó nếu người dùng cuộn chuột đến, họ sẽ thấy ảnh chất lượng thấp trước, rồi lazysizes sẽ thay thế ảnh chất lượng kém này bằng ảnh thực chất lượng cao. Nhiều trang web lớn như medium.com đang áp dụng kiểu lazy load ảnh này.

<style>
	.blur-up {
		-webkit-filter: blur(5px);
		filter: blur(5px);
		transition: filter 400ms, -webkit-filter 400ms;
	}
	.blur-up.lazyloaded {
		-webkit-filter: blur(0);
		filter: blur(0);
	}
</style>
<img src="lqip-src.jpg" data-src="image.jpg" class="lazyload blur-up" />
<!-- ... -->
<style>
	.fade-box .lazyload,
	 .fade-box .lazyloading {
		opacity: 0;
		transition: opacity 400ms;
	}
	.fade-box img.lazyloaded {
		opacity: 1;
	}
</style>
<div class="ratio-box fade-box">
	<img src="lqip-src.jpg" />
	<img data-src="image.jpg" class="lazyload" />
</div>

Để gia tăng chất lượng phần nhìn hơn nữa, thì ảnh chất lượng thấp sẽ được làm mờ ảo bằng CSS thông qua blur, còn để quá trình chuyển ảnh diễn ra nhẹ nhàng, ta cũng áp dụng CSS thông qua thuộc tính transition với khoảng thời gian tùy theo ý bạn, ở trên là 400 ms.

Dưới đây là trang mẫu áp dụng LQIP kết hợp CSS (với transition chỉ 200ms – blur up): https://static.kiencang.net/2020/lazysizes-demo-LQIP1.html (đây là mẫu LQIP thông thường, không phải ảnh đáp ứng).

Mẫu tương tự với transition 800ms blur up: https://static.kiencang.net/2020/lazysizes-demo-LQIP-800ms.html

Mẫu tương tự với transition 2000ms = 2s blur up (chỉ để bạn dễ quan sát, không nên làm trong thực tế vì quá trình chuyển tiếp với khoảng thời gian như thế sẽ hơi lâu): https://static.kiencang.net/2020/lazysizes-demo-LQIP-2000ms.html

Riêng với cái fade-box, tôi có thử nhưng không thành công (nó tải về cả hai ảnh), hiện không rõ tại sao: https://static.kiencang.net/2020/lazysizes-fade-box.html

Sử dụng LQIP sẽ làm tăng dung lượng tải về của trang (so với việc không dùng) do trang phải tải cả ảnh chờ chất lượng thấp và ảnh chất lượng cao. Nhưng điều này không thành vấn đề, vì mức độ gia tăng là nhỏ (hoặc rất nhỏ), trong khi nó đem đến khả năng cải thiện trải nghiệm của người dùng lên rất nhiều (và tất nhiên vẫn tăng tốc độ tải trang lúc ban đầu / initial page load time).

Nếu bạn muốn tự thử, có thể sử dụng công cụ này để tạo ảnh chất lượng thấp cho ảnh chất lượng cao của bạn: https://imagecompressor.com/ Nó có thể tải lên đồng thời 20 bức ảnh. Bạn nhớ chuyển sang chất lượng thấp nhất có thể:

chuyển ảnh chất lượng thấp

Ngoài ra bạn có thể dùng phần mềm máy bàn có tên Caesium nếu muốn áp dụng lên nhiều ảnh hơn cùng lúc (ngoài ra phần mềm không gặp vấn đề gì khi chuyển đổi ảnh có dung lượng lớn): https://saerasoft.com/caesium/

Điểm mấu chốt của LQIP là bạn phải làm thế nào để ảnh chất lượng thấp có dung lượng càng nhỏ càng tốt, vì ảnh này chỉ đóng vai trò ảnh đệm, nó chỉ cần có các khối hình mờ mờ là ổn rồi.

Các mẫu srcset transparent hiện đại

Kết hợp thuộc tính src thông thường với ảnh transparent (trong suốt) hoặc ảnh chất lượng thấp bằng giá trị srcset và thuộc tính data-srcset. Với cách này các trình duyệt hiện đại sẽ lazy load mà không tải thuộc tính src và tất cả những thứ khác sẽ chỉ đơn giản là dự phòng cho thuộc tính src ban đầu (không có lazyload). Mẫu đẹp mắt này có nguồn gốc từ tác giả @ivopetkov.

<img
    src="image3.jpg"
    srcset="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
	data-srcset="image3.jpg 600w,
            image1.jpg 220w,
	    image2.jpg 300w,
	    image4.jpg 900w"
	data-sizes="auto"
	class="lazyload" />

Dưới đây là mẫu áp dụng ảnh trong suốt: https://static.kiencang.net/2020/lazysizes-anh-trong-suot.html

Mẫu mã noscript

Trong trường hợp bạn lo lắng vấn đề JavaScript bị vô hiệu hóa, bạn có thể kết hợp mẫu đơn giản dưới đây với ảnh ở bên trong phần tử noscript.

<style>
	.no-js img.lazyload {
    	display: none;
    }
</style>
<!-- noscript pattern -->
<noscript>
	<img src="image.jpg" />
</noscript>
<img src="transparent.jpg" data-src="image.jpg" class="lazyload" />

Nhưng trước hết ở thẻ <html> bạn cần thêm class no-js:

<html class="no-js" lang="vi-VN"> 

Và thêm đoạn mã sau vào trong <head> để loại bỏ class no-js trong trường hợp JavaScript được kích hoạt:

<script>document.documentElement.classList.remove("no-js");</script>

Lưu ý: có mẫu noscript khác thay thế, bạn có thể xem thêm tại đây extension noscript.

Để giả lập việc tắt JavaScript trên trình duyệt Chrome bạn làm như sau. Trên thanh địa chỉ bạn copy đoạn này vào rồi nhấn enter:

chrome://settings/content/javascript

Rồi bạn tắt JS như hình dưới đây:

tắt JavaScript

Khi vô hiệu hóa JS thì lazysies không thể hoạt động, trong trường hợp đó nếu không có mã dự phòng <noscript> thì ảnh trên trang sẽ bị lỗi.

Nếu bạn sử dụng LQIP (https://static.kiencang.net/2020/lazysizes-demo-LQIP1.html), ảnh trên trang chỉ còn hiểu thị ảnh mờ, không còn hiển thị ảnh thật chất lượng cao nữa, kiểu như thế này:

lỗi không có javascript

Còn với trang áp dụng lazyload thông thường (https://static.kiencang.net/2020/lazysizes-demo1.html), thậm chí còn mất luôn ảnh:

ảnh không hiển thị do bị vô hiệu hóa JavaScript

Mẫu trang khắc phục hiện tượng vô hiệu hóa JavaScript: https://static.kiencang.net/2020/lazysizes-noscript.html

Hiện tượng lazy load vẫn bị biến mất trên trang vô hiệu hóa JavaScript, noscript chỉ giúp bạn khắc phục hiện tượng ảnh bị mất. Nếu bạn vẫn muốn lazy load ảnh trên trang bị vô hiệu hóa JS, chỉ có cách sử dụng lazy load cấp độ trình duyệt (native lazy loading).

P/S: Chuyện bị vô hiệu hóa JavaScript rất nghiêm trọng do trên thực tế rất nhiều trang web sử dụng JS như một chức năng thiết yếu. Nói cách khác, việc vô hiệu hóa JS gần như không thể xảy ra, chính xác hơn: rất hiếm người làm như vậy.

Thuộc tính [data-expand]

Thông thường lazysizes sẽ mở rộng khung nhìn trình duyệt để tải lười trước các ảnh/iframe – là những thành phần mà sẽ sớm đi vào khung nhìn trình duyệt. Giá trị này có thể được điều chỉnh bằng cách sử dụng tùy chọn expand (bạn xem phần 2 để biết cách dùng giá trị này).

Ngoài ra tùy chọn chung này có thể được ghi đè với thuộc tính data-expand cho từng phần tử. Điểm khác biệt so với tùy chọn chung expand là thuộc tính data-expand chấp nhận giá trị âm (Tất cả các giá trị, bao gồm cả 0).

Điều này đặc biệt hữu ích trong một số trường hợp:

<style>
.lazyload,
.lazyloading {
	opacity: 0;
}
.lazyloaded {
	opacity: 1;
	transition: opacity 300ms;
}
</style>
<div class="teaser lazyload" data-expand="-20">
    <img data-src="image.jpg" class="lazyload" />
    <h1>Teaser Title</h1>
    <p>...</p>
</div>

Tôi có thử với data-expand, nhưng làm sai gì đó không rõ nên không thấy khác biệt lắm so với không dùng: https://static.kiencang.net/2020/lazysizes-data-expand.html

Ở phần 2, tôi có nhiều ví dụ về expand, và nó hoạt động rất tốt.

CSS API

lazysizes thêm class có tên lazyloading trong khi ảnh tải về và thêm class lazyloaded sớm nhất có thể sau khi ảnh được tải xong. Điều này có thể được dùng để thêm các hiệu ứng unveil (tạm dịch: vén màn, tiết lộ, ý chỉ việc thể hiện ảnh thực cần lazy load):

/* làm mờ ảnh sau khi tải */
.lazyload,
.lazyloading {
	opacity: 0;
}
.lazyloaded {
	opacity: 1;
	transition: opacity 300ms;
}

Mẫu trang áp dụng cho ví dụ trên: https://static.kiencang.net/2020/lazysizes-css-api1.html

/* làm mờ ảnh trong khi tải và hiển thị một spinner đang tải dưới dạng ảnh background (tốt cho các ảnh dạng progressive) */
.lazyload {
	opacity: 0;
}
.lazyloading {
	opacity: 1;
	transition: opacity 300ms;
	background: #f7f7f7 url(loader.gif) no-repeat center;
}

Mẫu trang áp dụng cho ví dụ trên: https://static.kiencang.net/2020/lazysizes-css-api2.html

Cái loader.gif là ảnh động GIF để cho biết ảnh đang tải, nó chính là cái này: loading.gif (chỉ có điều ảnh GIF đang dùng hơi nặng, bạn nên sử dụng cái có dung lượng nhỏ hơn, chẳng hạn như cái này: small-loading.gif).

Kết quả là nếu người dùng đi đến phần ảnh đang tải, nó sẽ trông giống thế này:

ảnh đang tải

Tiện thể tôi làm luôn mẫu dành cho cái small loading (với transition 300 ms): https://static.kiencang.net/2020/lazysizes-css-api3.html (trông đẹp hơn thật).

Với transition 2000 ms, kết quả trông cũng không khác máy: https://static.kiencang.net/2020/lazysizes-css-api4.html

P/S: Hầu hết các ảnh sẽ tải nhanh đến nỗi mà bạn khó nhận ra biểu tượng của loading, chỉ trừ các ảnh nặng, hoặc trên kết nối chậm mới thấy.

Biểu tượng cho ảnh bị hỏng

Trong trường hợp bạn đang sử dụng thuộc tính alt nhưng không khai báo thuộc tính src / srcset hệ quả là bạn sẽ nhận được một biểu tượng là hình ảnh bị hỏng.

Có hai cách đơn giản để xử lý điều đó.

Hoặc bạn xác định src bằng ảnh base64 kiểu như:

src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="

Hoặc bạn thêm đoạn mã CSS sau:

img.lazyload:not([src]) {
	visibility: hidden;
}

(Mời bạn đọc tiếp phần 2)

Back to Top