CS ๊ณต๋ถ€ - front

[์›น/์ตœ์ ํ™”]Image Lazy Loading

Nuri-KSLV-II 2023. 2. 27. 14:24

๐Ÿ“Œ Image Lazy Loading์ด๋ž€?

ํŽ˜์ด์ง€ ์•ˆ์— ์žˆ๋Š” ์‹ค์ œ ์ด๋ฏธ์ง€๋“ค์ด ํ™”๋ฉด์— ๋ณด์—ฌ์งˆ ํ•„์š”๊ฐ€ ์žˆ์„ ๋•Œ ๋กœ๋”ฉ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์—ฐ์‹œํ‚ค๋Š” ๊ฒƒ


- ๋””๋ฐ”์ด์Šค ๋‚ด ๋ฆฌ์†Œ์Šค ํ™œ์šฉ๋„ ์ฆ๊ฐ€

- ์›น ์„ฑ๋Šฅ ์ตœ์ ํ™”

- EX. SPA(Sing Page Application) ๋‚ด์—์„œ ๋ฐ”๋กœ ๋ณด์—ฌ์งˆ ํ•„์š”๊ฐ€ ์—†๋Š” ์ด๋ฏธ์ง€๋ฅผ ์ง€์—ฐ ๋กœ๋”ฉ

 

โœ” ๋ฐฉ์‹

1. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ด์šฉํ•ด image load๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๊ธฐ

HTML

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

 

JS

document.addEventListener("DOMContentLoaded", function() {
  var lazyloadImages = document.querySelectorAll("img.lazy");    
  var lazyloadThrottleTimeout;
  
  function lazyload () {
    if(lazyloadThrottleTimeout) {
      clearTimeout(lazyloadThrottleTimeout);
    }    
    
    lazyloadThrottleTimeout = setTimeout(function() {
        var scrollTop = window.pageYOffset;
        lazyloadImages.forEach(function(img) {
            if(img.offsetTop < (window.innerHeight + scrollTop)) {
              //์—ฌ๊ธฐ ์ด๋ถ€๋ถ„์ด ๋ทฐํฌํŠธ์— ๋ณด์ผ ๋•Œ src ๊ฐ’ ๋„ฃ์–ด์ฃผ๋Š” ๋ถ€๋ถ„
              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);
});

 

 

2. Intersection Observer API

- Intersection Observer๋Š” ๋น„๊ต์  ์ตœ๊ทผ์— ๋‚˜์˜จ API๋กœ ์—˜๋ฆฌ๋จผํŠธ ์š”์†Œ๊ฐ€ ๋ทฐํฌํŠธ์— ๋“ค์–ด๊ฐ€๋Š” ๊ฒƒ์„ ๊ฐ์ง€ํ•˜๊ณ  ์•ก์…˜์„ ์ทจํ•˜๋Š” ๊ฒƒ์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์คŒ(๋Œ€์‹  ์—ฐ์‚ฐํ•ด์คŒ)

- ๋ธŒ๋ผ์šฐ์ € ํ˜ธํ™˜์„ฑ ํ™•์ธ ํ›„ ์‚ฌ์šฉ

 

JS

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

  if ("IntersectionObserver" in window) {
    lazyloadImages = document.querySelectorAll(".lazy");
    //Observer ์‚ฌ์šฉ
    var imageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        //intersecting์ด๋ž€ ๋Œ€์ƒ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ๋ฃจํŠธ(๋””ํดํŠธ๋Š” ์•„๋งˆ ๋ทฐํฌํŠธ)์™€ ๊ต์ฐจํ• ๋•Œ true๊ฐ’
        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);
    });
  } else {  
    var lazyloadThrottleTimeout;
    lazyloadImages = document.querySelectorAll(".lazy");
    
    function lazyload () {
      if(lazyloadThrottleTimeout) {
        clearTimeout(lazyloadThrottleTimeout);
      }    

      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);
  }
})

 

 

3. Native Lazy Loading

- chrome 76์—์„œ ์ง€์›

- ์ด๋ฏธ์ง€์— loading="lazy"๋งŒ ์ถ”๊ฐ€

- ์ง€์—ฐ ๋กœ๋”ฉ ๋  ๋•Œ ์ž๋ฆฌ ์ฐจ์ง€์˜ ๋ณ€๊ฒฝ์œผ๋กœ ์ธํ•œ ํƒ€ ์ฝ˜ํ…์ธ ์˜ ๋‚ด์šฉ ๋ฐ€๋ ค๋‚จ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ๊ณต๊ฐ„ ํฌ๊ธฐ ๋ถ€์—ฌ ๊ผญ ํ•ด์ค˜์•ผํ•จ

- ํƒ€ ๋ธŒ๋ผ์šฐ์ € ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ ์žˆ์Œ(์˜ˆ์‹œ ์‚ฌ์ดํŠธ : https://www.joongang.co.kr/society

 

HTML

<img src="…" loading="lazy" alt="…" width="200" height="200">

 

4. CSS ์†์„ฑ ์ค‘ background image ์‚ฌ์šฉ

 

HTML

<div id="container">
  <h3>Lazy loading CSS background images</h3>
  <p>์—„์ฒญ ๊ธด ๋กœ๋ ˜์ž…์ˆจ</p>
  <p>์—„์ฒญ ๊ธด ๋กœ๋ ˜์ž…์ˆจ</p>
  <div id="bg-image" class="lazy"></div>
  <p>
	๋กœ๋ ˜์ž…์ˆจ
  </p>
</div>

CSS

#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;
}

JS๋Š” ์˜ต์ €๋ฒ„์™€ ๊ฐ™์Œ

 

 

5. React.lazy

import React, { lazy } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

const CommonComponent = () => (
  <div>
    <LazyComponent />
  </div>
)

 

 

6. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

- yall.js

- lazysizes

 

 

โœ” ์ฃผ์˜ํ•  ์ 

- ์›นํŽ˜์ด์ง€ ์ƒ๋‹จ์— ์ด๋ฏธ์ง€๋Š” lazy loading ํ•˜์ง€ ์•Š์Œ

- ์ด๋ฏธ์ง€๊ฐ€ ๋ทฐํฌํŠธ์— ์™„์ „ํžˆ ๋“ค์–ด์˜ฌ ๋•Œ ๊ฐ€ ์•„๋‹Œ, ๋งˆ์ง„ ๊ฐ’์„ ์ฃผ์–ด์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณผ ๋•Œ๋ณด๋‹ค ๋กœ๋”ฉ ํŠธ๋ฆฌ๊ฑฐ ์‹œ์ ์„ ์‚ด์ง ๋” ๋นจ๋ฆฌ ์žก์•„์„œ placeholder๋ฅผ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ

- placeholder๋ฅผ ์“ฐ๋”๋ผ๋„, ๊ธฐ๋ณธ ์ด๋ฏธ์ง€์˜ ์ƒ‰์ƒ์„ ์ถ”์ถœํ•ด์„œ ๋น„์Šทํ•œ ์ƒ‰์ƒ์˜ placeholder ๋˜๋Š” ์ €ํ™”์งˆ์˜ placeholder๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€ ์šฉ๋Ÿ‰ ์ค„์ด๋ฉด์„œ ux ๋†’์ด๊ธฐ

 

 

์ฐธ๊ณ 

https://helloinyong.tistory.com/297