ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [이미지] Lazy Loading에 대한 고찰
    Javascript 2020. 2. 15. 14:33

    이 글은 하단 출처에서 발췌하여 필요한 부분만 따로 정리한 글입니다.

     

    이미 지연 로딩이 실행되는 것을 본 적이 있을 것입니다. 지연 로딩은 다음과 같이 진행됩니다.

    • 페이지에 도달하여 콘텐츠를 읽으면서 스크롤을 시작합니다.
    • 특정 지점에서 자리표시자 이미지를 표시 영역으로 스크롤합니다.
    • 자리표시자 이미지가 순간 최종 이미지로 교체됩니다.

    출처 : https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video?hl=ko

    <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="저는 이미지입니다!">

    현대의 브라우저는 Intersection observer API를 통해 요소 확인 작업을 수행하는 더욱 우수하고 효율적인 방식을 제공합니다.

    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 a more compatible method here
      }
    });

    예시 동영상

    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>
    .lazy-background {
      background-image: url("hero-placeholder.jpg"); /* Placeholder image */
    }
    
    .lazy-background.visible {
      background-image: url("hero.jpg"); /* The final image */
    }
    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);
        });
      }
    });

    video도 poster를 통해서 먼저 로딩되는 현상을 피해야 한다

    <video 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 컨텐츠는 source에 보관되기 때문에 다음과 같이 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 속성마다 자동으로 재생을 시작합니다.


    자바스크립트를 항상 이용할 수 있다고 가정해서는 안 됩니다. 이미지를 지연 로드하려면 자바스크립트를 사용할 수 없는 경우에 이미지를 data-* 속성에 넣어두었지만 다시 제대로 노출해주어야 합니다.

    <!-- An image that eventually gets lazy loaded by JavaScript -->
    <img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load.jpg" alt="저는 이미지입니다!">
    <!-- An image that is shown if JavaScript is turned off -->
    <noscript>
      <img src="image-to-lazy-load.jpg" alt="저는 이미지입니다!">
    </noscript>

    네이티브 레이지 로딩 속성 (loading="lazy")

    출처 : https://meetup.toast.com/posts/183

    위의 네이티브 레이지 로딩 속성이 사용 가능한 브라우저 및 플랫폼인지 아닌지의 체크도 시도해 볼 수 있겠습니다.

    if ('loading' in HTMLImageElement.prototype) alert("네이티브 레이지 로딩 지원함"); else alert("지원 안함");

    출처 : https://meetup.toast.com/posts/183

    위처럼 처리함으로써 얻게되는 이득은 모든 플랫폼 및 브라우저에서 레이지 로딩을 일으킬 수 있다는 것입니다.

     

    'Javascript' 카테고리의 다른 글

    JS 이벤트 루프(callback, setTimeout, queue, 싱글스레드)  (0) 2020.03.29
    JavaScript에서 Priavate 구현  (0) 2020.03.15
    var, let & const 이해하기  (0) 2019.12.15
    반복문 없이 반복문 하기  (0) 2019.09.14
    Javscript Callback  (0) 2019.09.12
Designed by Tistory.