Lazy Loading이란?

지연 로딩(Lazy Loading)은 초기 로딩 시간을 줄이고 페이지 로딩 속도를 개선하기 위한 기술로, 리소스들을 실제로 사용하는 시점에 로딩하는 것을 이릅니다. 특히, 이미지 최적화에 가장 많이 사용되는 기법입니다.

왜 Lazy Loading인가?

Lazy Loading을 사용하면 웹 페이지의 초기 로딩 속도가 개선되어 사용자들이 더 빠르게 페이지를 이용할 수 있습니다. 특히 이미지를 로딩하는데 소요되는 시간을 줄일 수 있어, 사용자들이 빠르게 이미지를 볼 수 있도록 해줍니다. 또한, 페이지에 필요한 리소스들을 미리 로딩하지 않고 필요할 때 로딩하기 때문에, 필요하지 않은 리소스들을 로딩하지 않아서 불필요한 네트워크 트래픽을 줄일 수 있습니다.

하지만, Lazy Loading을 적용할 때는 주의해야 할 점도 있습니다. 예를 들어, 페이지에 반드시 필요한 리소스들은 초기 로딩 시점에 로딩되어야 합니다. 또한, JavaScript를 통해 Lazy Loading을 구현할 때는 JavaScript를 지원하지 않는 브라우저에서는 Lazy Loading이 동작하지 않을 수 있습니다. 이러한 점들을 고려하여 적절하게 Lazy Loading을 적용하면, 웹 페이지의 성능을 개선할 수 있습니다.

Lazy Loading 을 이용한 이미지 최적화 기법

img 태그를 사용한 구현 방식

가장 일반적으로 사용되어지는 방식입니다.
지연 로딩을 적용시킬 요소를 감지하고 이벤트를 발생시키기 위한 트리거를 class에 지정합니다.

이미지 URL을 src 속성이 아닌, data-src에  할당합니다. <img> 태그의 src가 비어있기 때문에 웹 페이지에 접근했을 때 브라우저는 해당 이미지를 로딩하지 않습니다.

<img> 태그가 뷰포트에 들어온 경우 (즉, 사용자에게 보여지고 있는 경우)를 감지해서 커스텀 속성 data-src에 들어간 이미지 URL을 <img> 태그의 src에 넣어주면, 실제 사용되는 시점에서 이미지를 로딩할 수 있습니다.

JavaScript Throttle + EventHandler

  <img src="https://ik.imagekit.io/demo/img/image1.jpeg?tr=w-400,h-300" />
  <img src="https://ik.imagekit.io/demo/img/image2.jpeg?tr=w-400,h-300" />
  <img src="https://ik.imagekit.io/demo/img/image3.jpg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image5.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image6.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image7.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image8.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image9.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image10.jpeg?tr=w-400,h-300" />
document.addEventListener("DOMContentLoaded", function() {
  var lazyloadImages = document.querySelectorAll("img.lazy");    
  var lazyloadThrottleTimeout;

  function lazyload () {
    if(lazyloadThrottleTimeout) {
      clearTimeout(lazyloadThrottleTimeout);
    }    
 
    // scroll 이벤트로 인한 성능 저하가 일어나지 않도록 일정 시간 내 한 번만 실행되도록 Throttle 적용
    lazyloadThrottleTimeout = setTimeout(function() {
        var scrollTop = window.pageYOffset;
        lazyloadImages.forEach(function(img) {
            if(img.offsetTop < (window.innerHeight + scrollTop)) {
              img.src = img.dataset.src;
              img.classList.remove('lazy');
            }
        });
        if(lazyloadImages.length == 0) { 
          document.removeEventListener("scroll", lazyload);
          window.removeEventListener("resize", lazyload);
          window.removeEventListener("orientationChange", lazyload);
        }
    }, 20);
  }

  document.addEventListener("scroll", lazyload);
  window.addEventListener("resize", lazyload);
  window.addEventListener("orientationChange", lazyload);
});

Intersection Observer API

Intersection Observer API는 브라우저 API 중 하나로, 2016년 발표되었습니다.

뷰포트와 타겟 요소(element)의 교차(intersection) 정보를 제공하여 요소가 뷰포트에 교차되는지. 즉, 요소의 가시성 여부를 판별하는 역할을 합니다.

Intersection Observer API는 비동기적으로 실행되기 때문에, 웹 브라우저에서 짧은 시간 내 발생하는 수많은 이벤트를 동기적으로 실행시켜 메인 스레드에 부하를 일으는 scroll drag mouse 이벤트의 렌더링 성능 저하 문제 없이 사용할 수 있습니다.

document.addEventListener("DOMContentLoaded", function() {
  var lazyloadImages;    

  if ("IntersectionObserver" in window) {
    lazyloadImages = document.querySelectorAll(".lazy");
    var imageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          var image = entry.target;
          image.src = image.dataset.src;
          image.classList.remove("lazy");
          imageObserver.unobserve(image);
        }
      });
    });

    lazyloadImages.forEach(function(image) {
      imageObserver.observe(image);
    });
  }
})

Intersection Observer - 요소의 가시성 관찰

❗CSS Background Image 속성을 사용하여 구현 (w. Intersection Observer API)

#bg-image.lazy {
   background-image: none;
   background-color: #F1F1FA;
}

#bg-image {
  background-image: url("https://ik.imagekit.io/demo/img/image10.jpeg?tr=w-600,h-400");
  max-width: 600px;
  height: 400px;
}

<img> 대신 background-image 속성을 사용하여 이미지를 로드할 경우 브라우저 뷰포트에 들어오기 전까지 타겟 요소의 background-image를 숨겼다가, 해당 요소가 감지되면 .lazy 클래스를 삭제하는 것으로 구현할 수 있습니다.

브라우저 Native Lazy Loading를 이용하여 구현

Chrome 76 이상에서는 사용자 지정 지연 로딩 코드를 작성하거나 별도의 JavaScript 라이브러리를 사용할 필요 없이 loading 속성을 사용하여 이미지를 지연 로딩할 수 있습니다.

단, 이미지가 로드되는 동안 이미지의 크기를 브라우저가 알 수 없기 때문에, 모든 이미지에는 width와 height값이 지정되어 있어야 합니다.

<img src="image.png" loading="lazy" alt="" width="200" height="200">

Reference
① Lazy Loading Images - The Complete Guide
https://imagekit.io/blog/lazy-loading-images-complete-guide/#how-to-test-if-lazy-loading-is-working

https://helloinyong.tistory.com/297

② 웹용 브라우저 수준 이미지 지연 로딩 https://web.dev/i18n/ko/browser-level-image-lazy-loading/

③ 실무에서 느낀 점을 곁들인 Intersection Observer API 정리 https://velog.io/@elrion018/실무에서-느낀-점을-곁들인-Intersection-Observer-API-정리

④ Intersection Observer API의 사용법과 활용 방법 http://blog.hyeyoonjung.com/2019/01/09/intersectionobserver-tutorial/

⑤ Intersection Observer API MDN https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

0개의 댓글

Powered by GraphCDN, the GraphQL CDN