Ленивая загрузка видео

Опубликовано: 16 августа 2019 г.

Как и в случае с элементами изображения , вы также можете захотеть отложенную загрузку видео. Видео обычно загружаются с помощью элемента <video> , хотя для видео, размещенных на других сервисах, таких как YouTube, они могут использовать <iframe> (в этом случае ознакомьтесь со статьей об отложенной загрузке iframes ).

Способ отложенной загрузки <video> зависит от варианта использования, поскольку существует несколько разных решений.

Обычно лучше избегать автоматического воспроизведения видео, поскольку в этом случае контроль остается за пользователем. В этих случаях указание атрибута preload в элементе <video> — лучший способ избежать загрузки всего видео:

<video controls 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>

В предыдущем примере используется атрибут preload со значением none , чтобы браузеры не могли предварительно загружать какие-либо видеоданные. Атрибут poster дает элементу <video> заполнитель, который будет занимать пространство во время загрузки видео.

В большинстве браузеров по умолчанию preload metadata , а часть видео предварительно загружается с использованием заголовка Content-Range . Это может привести к загрузке большего количества данных, чем хотелось бы, особенно если заголовок Content-Range не поддерживается браузером. Даже если это поддерживается, браузеры не могут знать, в каких байтах хранятся метаданные, и они не могут храниться в начале файла. Поэтому лучший шанс избежать загрузки видео — указать none и использовать preload="none" .

Это можно дополнительно улучшить, чтобы предварительно загружать метаданные, когда пользователь наводит курсор на видео с помощью атрибута onmouseenter (или с помощью эквивалентного обработчика событий mouseenter ):

<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>

Это не только уменьшает задержку, когда пользователь начинает воспроизводить видео, но и показывает продолжительность видео, как только он это сделает.

Видео могут претендовать на звание кандидатов LCP . Изображение poster будет загружаться быстрее, чем видео, поэтому, если это кандидат на LCP, вам следует использовать изображение постера, но также предварительно загрузить его со значением атрибута fetchpriority "high" :

<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>

Для видео, выступающего в качестве замены анимированного GIF.

Видео с автовоспроизведением чаще всего используются для быстрой анимации в стиле GIF. Хотя анимированные GIF-файлы широко используются, они уступают видео-эквивалентам во многих отношениях, особенно по размеру файла. Анимированные GIF-файлы могут занимать несколько мегабайт данных. Видео одинакового визуального качества, как правило, намного меньше.

Использовать элемент <video> в качестве замены анимированного GIF-файла не так просто, как элемент <img> . Анимированные GIF-файлы имеют три характеристики:

  1. Они воспроизводятся автоматически при загрузке.
  2. Они зацикливаются непрерывно ( хотя это не всегда так ).
  3. У них нет звуковой дорожки.

Достижение этого с помощью элемента <video> выглядит примерно так:

<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>

Атрибуты autoplay , muted и loop говорят сами за себя. playsinline необходим для автоматического воспроизведения в iOS . Теперь у вас есть полезная замена видео в формате GIF, которая работает на всех платформах. Но как сделать ленивую загрузку? Для начала измените разметку <video> соответствующим образом:

<video class="lazy" autoplay muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
  <source data-src="one-does-not-simply.webm" type="video/webm">
  <source data-src="one-does-not-simply.mp4" type="video/mp4">
</video>

Вы заметите добавление атрибута poster , который позволяет указать заполнитель, который будет занимать пространство элемента <video> до тех пор, пока видео не будет загружено отложенно. Как и в примерах отложенной загрузки <img> , сохраните URL-адрес видео в атрибуте data-src каждого элемента <source> . Далее используйте код JavaScript, аналогичный примерам отложенной загрузки изображений на основе Intersection Observer:

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) {
          for (var source in video.target.children) {
            var videoSource = video.target.children[source];
            if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
              videoSource.src = videoSource.dataset.src;
            }
          }

          video.target.load();
          video.target.classList.remove("lazy");
          lazyVideoObserver.unobserve(video.target);
        }
      });
    });

    lazyVideos.forEach(function(lazyVideo) {
      lazyVideoObserver.observe(lazyVideo);
    });
  }
});

При отложенной загрузке элемента <video> вам необходимо перебрать все дочерние элементы <source> и поменять их атрибуты data-src на атрибуты src . Как только вы это сделаете, вам нужно запустить загрузку видео, вызвав метод load элемента, после чего мультимедиа начнет автоматически воспроизводиться в соответствии с атрибутом autoplay .

Используя этот метод, вы получаете видеорешение, которое имитирует поведение анимированных GIF-файлов, но не требует такого же интенсивного использования данных, как анимированные GIF-файлы, и вы можете отложенно загружать этот контент.

Ленивая загрузка библиотек

Следующие библиотеки могут помочь вам в ленивой загрузке видео:

  • vanilla-lazyload и lozad.js — сверхлегкие варианты, использующие только Intersection Observer. Таким образом, они очень производительны, но их необходимо будет заполнить полифилом, прежде чем вы сможете использовать их в старых браузерах.
  • yall.js — это библиотека, которая использует Intersection Observer и использует обработчики событий. Он также может отложенно загружать изображения poster используя атрибут data-poster .
  • Если вам нужна библиотека отложенной загрузки, специфичная для React, вы можете рассмотреть возможность реакции-lazyload . Хотя он не использует Intersection Observer, он предоставляет знакомый метод отложенной загрузки изображений для тех, кто привык разрабатывать приложения с помощью React.

Каждая из этих библиотек отложенной загрузки хорошо документирована и содержит множество шаблонов разметки для различных задач отложенной загрузки.