Ngày xuất bản: 16 tháng 8 năm 2019, Cập nhật lần gần đây nhất: 2 tháng 7 năm 2026
Giống như các phần tử hình ảnh, bạn cũng có thể muốn tải từng phần video. Video thường được tải bằng phần tử <video>, mặc dù đối với các video được lưu trữ trên các dịch vụ khác như YouTube, chúng có thể sử dụng <iframe> (trong trường hợp đó, hãy xem bài viết về việc tải từng phần iframe).
Cách tải từng phần <video> phụ thuộc vào trường hợp sử dụng, vì có một số giải pháp khác nhau.
Sử dụng thuộc tính loading
Trình duyệt đã bắt đầu hỗ trợ thuộc tính loading trên các phần tử đa phương tiện (<video> và <audio>). Khi được hỗ trợ, điều này có nghĩa là cả nội dung đa phương tiện và mọi hình ảnh áp phích đều tự động được tải từng phần chỉ bằng cách thêm thuộc tính loading="lazy":
<video controls loading="lazy" preload="none" poster="one-does-not-simply-placeholder.jpg">
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Việc sử dụng loading="lazy" sẽ ngăn hình ảnh poster tải xuống cho đến khi ở trong hoặc gần khung nhìn, sau đó sẽ sử dụng thuộc tính preload để quyết định tải bao nhiêu video. Điều này cũng có nghĩa là video autoplay sẽ không tự động phát cho đến khi ở trong hoặc gần khung nhìn. Thuộc tính loading="lazy" hoạt động với các thuộc tính poster, preload và autoplay và không thay thế nhu cầu sử dụng các thuộc tính này.
Các trình duyệt không hỗ trợ thuộc tính loading trên các phần tử đa phương tiện sẽ bỏ qua thuộc tính này, dẫn đến việc hình ảnh poster tải xuống ngay lập tức và video tải xuống dựa trên thuộc tính preload mà chúng ta sẽ đề cập tiếp theo.
Sử dụng thuộc tính preload để tải từng phần video không tự động phát
Việc tránh các video tự động phát thường là phương pháp hay nhất vì người dùng có thể kiểm soát. Trong những trường hợp này, việc chỉ định thuộc tính preload trên phần tử <video> là cách tốt nhất để tránh tải toàn bộ video cho đến khi cần:
<video controls loading="lazy" preload="none" poster="one-does-not-simply-placeholder.jpg">
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Ví dụ trước sử dụng thuộc tính preload có giá trị là none để ngăn trình duyệt tải trước bất kỳ dữ liệu video nào, ngay cả khi ở trong khung nhìn. Thuộc tính poster cung cấp cho phần tử <video> một phần giữ chỗ sẽ chiếm không gian trong khi video tải xuống.
Trong hầu hết các trình duyệt, preload mặc định là metadata và một phần của video được tải trước bằng tiêu đề Content-Range. Điều này có thể dẫn đến việc tải xuống nhiều dữ liệu hơn mong muốn – trình duyệt không thể biết các byte được lưu trữ ở đâu và có thể không được lưu trữ ở đầu tệp. Do đó, cách tốt nhất để tránh tải video là sử dụng preload="none".
Bạn có thể cải thiện hơn nữa để tải trước siêu dữ liệu khi người dùng di chuột qua video bằng thuộc tính onmouseenter (hoặc với trình xử lý sự kiện mouseenter tương đương):
<video controls
loading="lazy"
preload="none"
poster="one-does-not-simply-placeholder.jpg"
onmouseenter="event.target.setAttribute('preload','metadata')">
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Điều này không chỉ giảm độ trễ khi người dùng phát video mà còn cho biết thời lượng của video ngay khi họ.
Video có thể đủ điều kiện là ứng cử viên LCP. Hình ảnh poster sẽ tải xuống nhanh hơn video. Vì vậy, khi đây là ứng cử viên LCP, bạn nên sử dụng hình ảnh áp phích, nhưng cũng tải trước hình ảnh đó bằng giá trị thuộc tính fetchpriority là "high", vì tại thời điểm viết bài này, bạn không thể chỉ định fetchpriority cho các thuộc tính áp phích:
<link rel="preload" href="one-does-not-simply-placeholder.jpg" as="image" fetchpriority="high">
<video controls preload="none"
poster="one-does-not-simply-placeholder.jpg"
onmouseenter="event.target.setAttribute('preload','metadata')">
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Video là các phần tử LCP không nên sử dụng loading="lazy" – giống như cách bạn không nên tải từng phần hình ảnh LCP video.
Đối với video đóng vai trò thay thế ảnh GIF động
Video tự động phát thường được dùng cho ảnh động nhanh theo kiểu GIF. Mặc dù ảnh GIF động được sử dụng rộng rãi, nhưng chúng không bằng video tương đương về nhiều mặt, đặc biệt là về kích thước tệp. Ảnh GIF động có thể kéo dài đến vài megabyte dữ liệu. Video có chất lượng hình ảnh tương tự thường nhỏ hơn nhiều.
Việc sử dụng phần tử <video> để thay thế ảnh GIF động không đơn giản như phần tử <img>. Ảnh GIF động có 3 đặc điểm:
- Chúng tự động phát khi được tải.
- Chúng lặp lại liên tục (mặc dù không phải lúc nào cũng như vậy).
- Chúng không có bản nhạc âm thanh.
Để đạt được điều này bằng phần tử <video>, bạn cần làm như sau:
<video autoplay muted loop playsinline>
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Thuộc tính loading="lazy" tránh tải video cho đến khi gần khung nhìn. Các thuộc tính autoplay, muted và loop rất dễ hiểu. playsinline là cần thiết để tự động phát trong iOS.
Giờ đây, bạn đã có một video thay thế ảnh GIF có thể sử dụng được trên nhiều nền tảng. Nhưng làm cách nào để tải từng phần video đó?
Đối với các trình duyệt hỗ trợ tính năng này, loading="lazy" là lựa chọn dễ nhất:
<video loading="lazy" autoplay muted loop playsinline>
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Để hỗ trợ tải từng phần video trong các trình duyệt khác, bạn cần sử dụng JavaScript và sửa đổi đánh dấu <video> cho phù hợp:
<video class="lazy" preload="none" controls muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Bạn sẽ thấy việc xoá autoplay và thêm các thuộc tính class="lazy", preload="none" và poster, cho phép bạn chỉ định một phần giữ chỗ để chiếm không gian của phần tử <video> cho đến khi video được tải từng phần. Sau đó, chúng tôi sử dụng JavaScript Intersection Observer để bật lại tính năng tự động phát:
document.addEventListener("DOMContentLoaded", function() {
var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));
if ("IntersectionObserver" in window) {
var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(video) {
if (video.isIntersecting) {
video.target.removeAttribute('preload');
video.target.removeAttribute('controls');
video.target.autoplay = true;
video.target.classList.remove("lazy");
lazyVideoObserver.unobserve(video.target);
}
});
});
lazyVideos.forEach(function(lazyVideo) {
lazyVideoObserver.observe(lazyVideo);
});
}
});
Khi sử dụng phương thức này, video sẽ không tự động phát theo mặc định và chỉ khi trình quan sát giao điểm phát hiện video đang vào khung nhìn. Ngoài ra, thuộc tính controls xử lý các trường hợp khi JavaScript không thành công. Điều này có nghĩa là bạn có một giải pháp video mô phỏng hành vi của ảnh GIF động, nhưng không làm phát sinh mức sử dụng dữ liệu cao như ảnh GIF động và bạn có thể tải từng phần nội dung đó.
Thư viện tải từng phần
Các thư viện sau đây có thể giúp bạn tải từng phần video:
- vanilla-lazyload và lozad.js là các lựa chọn siêu nhẹ chỉ sử dụng Intersection Observer. Do đó, chúng có hiệu suất cao, nhưng cần được polyfill trước khi bạn có thể sử dụng chúng trên các trình duyệt cũ.
- Nếu bạn cần một thư viện tải từng phần dành riêng cho React, bạn có thể cân nhắc react-lazyload. Mặc dù không sử dụng Intersection Observer, nhưng thư viện này có cung cấp một phương thức quen thuộc để tải từng phần hình ảnh cho những người quen phát triển ứng dụng bằng React.
Mỗi thư viện tải từng phần này đều được ghi lại đầy đủ, với nhiều mẫu đánh dấu cho các nỗ lực tải từng phần khác nhau của bạn.
Khi thuộc tính loading cho <video> có trong nhiều trình duyệt hơn, chúng tôi hy vọng các giải pháp JavaScript (bao gồm cả thư viện) sẽ được sử dụng ít hơn để ưu tiên các giải pháp tích hợp, ngoại trừ những giải pháp muốn kiểm soát nhiều hơn mức cho phép.