동영상 지연 로드 중

게시일: 2019년 8월 16일

이미지 요소와 마찬가지로 동영상도 지연 로드할 수 있습니다. 동영상은 일반적으로 <video> 요소로 로드되지만 YouTube와 같은 다른 서비스에서 호스팅되는 동영상의 경우 <iframe>를 사용할 수 있습니다 (이 경우 지연 로드 iframe의 도움말을 참고하세요).

<video>를 지연 로드하는 방법은 사용 사례에 따라 다릅니다. 몇 가지 솔루션이 있기 때문입니다.

동영상 자동재생은 사용자에게 제어권을 넘겨주므로 일반적으로 피하는 것이 좋습니다. 이 경우 <video> 요소에서 preload 속성을 지정하는 것이 전체 동영상을 로드하지 않는 가장 좋은 방법입니다.

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

이전 예에서는 값이 nonepreload 속성을 사용하여 브라우저가 어떤 동영상 데이터도 미리 로드하지 못하도록 합니다. 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 이미지는 동영상보다 더 빠르게 로드되므로 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는 수 MB 범위의 데이터로 늘어날 수 있습니다. 유사한 시각 품질의 동영상은 훨씬 작습니다.

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

동영상이 지연 로드될 때까지 <video> 요소의 공간을 차지하는 자리표시자를 지정할 수 있는 poster 속성이 추가된 것을 볼 수 있습니다. <img> 지연 로딩 예시와 마찬가지로 각 <source> 요소의 data-src 속성에 동영상 URL을 보관합니다. 그런 다음 Intersection Observer 기반 이미지 지연 로드 예와 유사한 JavaScript 코드를 사용합니다.

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-lazyloadlozad.js는 Intersection Observer만 사용하는 초경량 옵션입니다. 따라서 성능은 매우 우수하지만 구형 브라우저에서 사용하기 전에 폴리필해야 합니다.
  • yall.js는 Intersection Observer를 사용하고 이벤트 핸들러로 대체되는 라이브러리입니다. data-poster 속성을 사용하여 동영상 poster 이미지를 지연 로드할 수도 있습니다.
  • React 특정 지연 로딩 라이브러리가 필요한 경우 react-lazyload를 고려해 볼 수 있습니다. Intersection Observer를 사용하지는 않지만, React를 통한 애플리케이션 개발에 익숙한 개발자를 위해 친숙한 지연 로드 이미지 방식을 제공합니다.

각 지연 로딩 라이브러리는 꼼꼼하게 문서화되어 있으며, 다양한 지연 로딩 시도를 위한 수많은 마크업 패턴이 있습니다.