이미지 지연 로드

이미지는 HTML에서 <img> 요소 또는 CSS 배경 이미지로 인라인으로 웹페이지에 표시될 수 있습니다. 이 게시물에서는 두 가지 유형의 이미지를 모두 지연 로드하는 방법을 알아봅니다.

인라인 이미지

가장 일반적인 지연 로드 후보는 <img> 요소에 사용되는 이미지입니다. 인라인 이미지에는 여러 브라우저 간 최상의 호환성을 위해 함께 사용할 수 있는 세 가지 지연 로드 옵션이 있습니다.

브라우저 수준의 지연 로드 사용

Chrome과 Firefox는 모두 loading 속성을 사용하여 지연 로드를 지원합니다. 이 속성은 <img> 요소 및 <iframe> 요소에도 추가할 수 있습니다. lazy 값은 이미지가 표시 영역에 있으면 즉시 이미지를 로드하고 사용자가 이미지 근처로 스크롤하면 다른 이미지를 가져오도록 브라우저에 지시합니다.

브라우저 지원에 관한 자세한 내용은 MDN 브라우저 호환성 표의 loading 필드를 참고하세요. 브라우저가 지연 로드를 지원하지 않으면 속성이 무시되고 이미지가 정상적으로 로드됩니다.

대부분의 웹사이트에서 이 속성을 인라인 이미지에 추가하면 성능이 향상되고 사용자가 스크롤하지 않을 이미지를 로드하는 작업이 줄어듭니다. 이미지 수가 많고 지연 로드 이점을 지원하지 않는 브라우저 사용자에게도 이를 제공하려면 다음에 설명된 방법 중 하나와 결합해야 합니다.

자세한 내용은 웹용 브라우저 수준의 지연 로드를 참고하세요.

Intersection Observer 사용

<img> 요소의 지연 로드를 폴리필하기 위해 JavaScript를 사용하여 표시 영역에 있는지 확인합니다. 두 속성의 경우 src (경우에 따라 srcset) 속성이 원하는 이미지 콘텐츠의 URL로 채워집니다.

이전에 지연 로드 코드를 작성한 적이 있다면 scroll 또는 resize와 같은 이벤트 핸들러를 사용하여 이미 작업을 완료했을 수 있습니다. 이 방법은 여러 브라우저에서 가장 잘 호환되지만, 최신 브라우저에서는 Intersection Observer API를 통해 요소 공개 상태를 확인하는 작업을 더 효율적으로 할 수 있는 효율적인 방법입니다.

Intersection Observer는 다양한 이벤트 핸들러에 의존하는 코드보다 더 쉽게 사용하고 읽을 수 있습니다. 지루한 요소 가시성 감지 코드를 작성하는 대신 watch 요소에 관찰자를 등록하기만 하면 되기 때문입니다. 이제 요소가 표시될 때 실행할 작업을 결정하기만 하면 됩니다. 지연 로드된 <img> 요소의 기본 마크업 패턴을 다음과 같이 가정해 보겠습니다.

<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">

이 마크업에서 중점을 두어야 할 세 가지 관련 항목이 있습니다.

  1. class 속성: JavaScript에서 요소를 선택하는 데 사용됩니다.
  2. src 속성: 페이지가 처음 로드될 때 표시되는 자리표시자 이미지를 참조합니다.
  3. data-srcdata-srcset 속성: 요소가 표시 영역에 있으면 로드할 이미지의 URL이 포함된 자리표시자 속성입니다.

이제 자바스크립트에서 Intersection Observer를 사용하여 다음 마크업 패턴으로 이미지를 지연 로드하는 방법을 알아보겠습니다.

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to event handlers here
  }
});

문서의 DOMContentLoaded 이벤트에서 이 스크립트는 lazy 클래스가 있는 모든 <img> 요소의 DOM을 쿼리합니다. Intersection Observer를 사용할 수 있는 경우 img.lazy 요소가 표시 영역에 들어올 때 콜백을 실행하는 새 관찰자를 만듭니다.

Intersection Observer는 모든 최신 브라우저에서 사용할 수 있습니다. 따라서 loading="lazy"의 폴리필로 사용하면 대부분의 방문자가 지연 로드를 사용할 수 있습니다.

CSS의 이미지

웹페이지에서 이미지를 사용하는 가장 일반적인 방법은 <img> 태그이지만 CSS background-image 속성 (및 기타 속성)을 통해서도 이미지를 호출할 수 있습니다. 브라우저 수준의 지연 로드는 CSS 배경 이미지에 적용되지 않으므로 지연 로드할 배경 이미지가 있는 경우 다른 방법을 고려해야 합니다.

표시 여부와 관계없이 로드되는 <img> 요소와 달리 CSS의 이미지 로드 동작은 더 많은 추측을 바탕으로 처리됩니다. 문서 및 CSS 객체 모델렌더링 트리가 빌드되면 브라우저는 외부 리소스를 요청하기 전에 CSS가 문서에 어떻게 적용되는지 검사합니다. 외부 리소스와 관련된 CSS 규칙이 현재 구성된 대로 문서에 적용되지 않는다고 브라우저에서 판단한 경우에는 이를 요청하지 않습니다.

이 추측 동작은 JavaScript를 사용하여 요소가 표시 영역 내에 있는지 확인하고 이후에 배경 이미지 호출을 위한 스타일 지정을 적용하는 클래스를 해당 요소에 적용함으로써 CSS에서 이미지 로드를 지연하는 데 사용할 수 있습니다. 이렇게 하면 초기 로드가 아닌 필요할 때 이미지가 다운로드됩니다. 예를 들어 큰 히어로 배경 이미지가 포함된 요소를 살펴보겠습니다.

<div class="lazy-background">
  <h1>Here's a hero heading to get your attention!</h1>
  <p>Here's hero copy to convince you to buy a thing!</p>
  <a href="/buy-a-thing">Buy a thing!</a>
</div>

div.lazy-background 요소는 일반적으로 일부 CSS에서 호출한 히어로 배경 이미지를 포함합니다. 그러나 이 지연 로드 예에서는 표시 영역에 있을 때 요소에 추가된 visible 클래스를 통해 div.lazy-background 요소의 background-image 속성을 격리할 수 있습니다.

.lazy-background {
  background-image: url("hero-placeholder.jpg"); /* Placeholder image */
}

.lazy-background.visible {
  background-image: url("hero.jpg"); /* The final image */
}

여기에서 JavaScript를 사용하여 요소가 표시 영역에 있는지 확인하고 (Intersection Observer 사용) visible 클래스를 그때 div.lazy-background 요소에 추가합니다. 그러면 이미지가 로드됩니다.

document.addEventListener("DOMContentLoaded", function() {
  var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));

  if ("IntersectionObserver" in window) {
    let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          entry.target.classList.add("visible");
          lazyBackgroundObserver.unobserve(entry.target);
        }
      });
    });

    lazyBackgrounds.forEach(function(lazyBackground) {
      lazyBackgroundObserver.observe(lazyBackground);
    });
  }
});

최대 콘텐츠 렌더링 시간 (LCP)에 미치는 영향

지연 로드는 이미지가 실제로 필요할 때 로드되는 것을 지연시켜 시작 시 전반적인 데이터 사용량과 네트워크 경합을 모두 줄이는 탁월한 최적화 기능입니다. 이렇게 하면 시작 시간을 개선하고 이미지 디코딩에 필요한 시간을 단축하여 기본 스레드에서의 처리를 줄일 수 있습니다.

그러나 지연 로드는 사용자가 이 기법을 너무 애용하면 웹사이트의 콘텐츠가 포함된 최대 페인트 LCP에 부정적인 영향을 미칠 수 있는 기법입니다. 한 가지 피해야 할 사항은 시작 시 표시 영역에 있는 이미지의 지연 로드를 피하는 것입니다.

JavaScript 기반 지연 로더를 사용할 때는 표시 영역 내 이미지의 지연 로드를 피하는 것이 좋습니다. 이러한 솔루션은 data-src 또는 data-srcset 속성을 srcsrcset 속성의 자리표시자로 사용하는 경우가 많기 때문입니다. 여기서 문제는 시작 중에 브라우저 미리 로드 스캐너가 이미지를 찾을 수 없어 이러한 이미지의 로드가 지연된다는 점입니다.

표시 영역 내 이미지를 지연 로드하기 위해 브라우저 수준의 지연 로드를 사용해도 역효과를 낼 수 있습니다. loading="lazy"가 표시 영역 내 이미지에 적용되면 브라우저가 이미지가 표시 영역에 있음을 확인할 때까지 해당 이미지가 지연되며, 이는 페이지의 LCP에 영향을 줄 수 있습니다.

시작 중에 표시 영역에 표시되는 이미지를 지연 로드하면 안 됩니다. 사이트의 LCP에 부정적인 영향을 주어 사용자 경험에 부정적인 영향을 미치는 패턴입니다. 시작할 때 이미지가 필요한 경우 지연 로드를 사용하지 않고 가능한 한 빨리 이미지를 로드하세요.

라이브러리 지연 로드

가능하면 브라우저 수준의 지연 로드를 사용해야 하지만, 이 옵션이 불가능한 상황(예: 상당수의 사용자가 여전히 이전 브라우저에 의존하고 있음)에 처한 경우 다음 라이브러리를 사용하여 이미지를 지연 로드할 수 있습니다.

  • pausesizes는 이미지와 iframe을 지연 로드하는 모든 기능을 갖춘 지연 로드 라이브러리입니다. 이 메서드가 사용하는 패턴은 <img> 요소의 lazyload 클래스에 자동으로 바인딩되고 data-src 또는 data-srcset 속성에 이미지 URL을 지정해야 한다는 점에서 여기에 나온 코드 예시와 매우 유사합니다. 이미지 URL의 콘텐츠는 각각 src 또는 srcset 속성으로 교체됩니다. Intersection Observer (폴리필 가능)를 사용하며, 여러 플러그인으로 확장하여 동영상 지연 로드와 같은 작업을 할 수 있습니다. 지연 크기 사용에 관해 자세히 알아보세요.
  • vanilla-lazyload는 이미지, 배경 이미지, 동영상, iframe, 스크립트를 지연 로드하기 위한 간단한 옵션입니다. Intersection Observer를 활용하고 반응형 이미지를 지원하며 브라우저 수준의 지연 로드를 사용 설정합니다.
  • lozad.js는 Intersection Observer만 사용하는 또 다른 간단한 옵션입니다. 따라서 성능이 우수하지만 이전 브라우저에서 사용하려면 먼저 폴리필해야 합니다.
  • React 관련 지연 로드 라이브러리가 필요한 경우 react-latencyload를 고려하세요. Intersection Observer를 사용하지는 않지만 React로 애플리케이션을 개발하는 데 익숙한 사용자에게 익숙한 지연 로드 이미지 방법을 제공합니다.