Image Lazy Loading(이미지 지연 로딩)

NSH·2022년 4월 27일
3

개인적으로 공부하면서 블로그를 작성하고 있으므로 내용이 정확하지 않을 수 있습니다.
잘못된 부분은 지적해주시면 개발자로서 성장하는데 많은 도움이 될 것 같습니다. 😀

Intersection Observer API(교차 관찰자 API)를 공부한 것을 바탕으로 웹 성능 최적화를 위한 이미지 지연 로딩을 구현해 보겠습니다.

이미지 지연 로딩 이란?

이미지 지연 로딩은 웹 페이지 내부의 실제 이미지들이 실제로 화면에 보여질 필요가 있을 때 로딩을 할 수 있도록하는 기법이다. 웹 페이지 내에서 바로 로딩을 하지 않고 로딩 시점을 뒤로 미루는 것이라고 볼 수 있다.

사용 이유

성능 향상

페이지 초기 로딩 시 필요한 이미지의 수를 줄여 리소스 다운로드 용량을 줄일 수 있으며 불필요한 이미지 리소스 요청을 줄임으로써 다른 리소스들을 더 빠르게 처리할 수 있다. 즉, 사용자가 더 빠르게 페이지를 볼 수 있도록 도와준다.

비용 감소

이미지 리소스 전달은 주로 전송 바이트 수에 기반하여 비용이 청구된다. 이미지 지연 로딩은 이미지가 보여지지 않으면 절대 로딩하지 않으므로, 페이지 내에서 전달할 총 바이트를 줄일 수 있다. 따라서 비용을 감소 시킬 수 있다.

적용 방법

아래 두 가지 방법으로 이미지 지연 로딩을 구현해 볼 것이다.

img tag loading="lazy" 속성

loading 속성은 브라우저의 이미지 로드 시점 여부를 결정 할 수 있다. loading 속성의 값으로 lazy 를 사용하면 브라우저 스크롤에 반응해서 뷰포트 영역에 근접할 때 이미지를 로딩한다.

브라우저는 이미지가 뷰포트 영역에 교차할 때 로딩하지 않고 조금 더 미리 로딩한다. 주의할 사항은 아래 예제는 세로 스크롤을 하는 페이지이기 때문에 이미지에 높이 값이 없으면 지연 로딩이 동작하지 않는다.

// example code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        img {
            width: 400px;
            height: 1200px;
            padding: 100px 0;
        }
    </style>
</head>
<body>
    <img src="./images/img_1.jpg" loading="lazy"/>
    <img src="./images/img_2.jpg" loading="lazy"/>
    <img src="./images/img_3.jpg" loading="lazy"/>
    <img src="./images/img_4.jpg" loading="lazy"/>
    <img src="./images/img_5.jpg" loading="lazy"/>
    <img src="./images/img_6.jpg" loading="lazy"/>
</body>
</html>

Intersection Observer API(교차 관찰자 API)

Intersection Observer API(교차 관찰자 API) 로 이미지 지연 로딩 구현은 아래와 같은 순서로 동작한다.

  1. Intersection Observer의 options 객체 생성
    • root에 타겟 요소의 가시성을 확인할 뷰포트 요소
    • rootMargin: root의 각 측면의 영역을 수측 또는 증가
    • threshold: observer의 callback이 실행될 타겟 요소의 가시성 퍼센티지
  2. Intersection Observer의 callback 함수 생성
    • 타겟 요소와 root가 교차된 상태인지의 여부 확인
    • 교차된 타겟 요소의 dataset에 등록된 이미지 주소를 src에 할당하여 이미지 로딩
    • 이미지 로딩이 완료된 타겟 요소는 관측 요소에서 제외한다.
  3. IntersectionObserver(callback, options) 인스턴스 생성
  4. IntersectionObserver 인스턴스에 타겟 요소들을 등록
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>이미지 지연 로딩(Intersection Observer)</title>
    <style>
        img {
            display: block;
            width: 800px;
            height: 800px;
        }
    </style>
    <script>
      	// 페이지의 리소스 로드가 완료되었을 때 실행
        window.onload = function() {
            const imgs = document.querySelectorAll('img');  

      		// IntersectionObserver options
            const options = {
      			// default browser viewport
                root: null, 
                threshold: 0.5 
            };

      		// IntersectionObserver callback
            const callback = function(entries, Observer) {
                entries.forEach(entry => {
                    if(entry.isIntersecting) {
                        Observer.unobserve(entry.target);
                        entry.target.src = entry.target.dataset.src;

                    }
                });
            }

      		// IntersectionObserver 인스턴스 생성
            let observer = new IntersectionObserver(callback, options);

      		// 타겟 요소를 순회하면서 관찰을 시작하도록 설정
            for(let i = 0; i < imgs.length; i++) {
                observer.observe(imgs[i]);
            }
        }
    </script>
</head>
<body>
    <img data-src="./images/img_1.jpg" alt="배경화면"/>
    <img data-src="./images/img_2.jpg" alt="배경화면"/>
    <img data-src="./images/img_3.jpg" alt="배경화면"/>
    <img data-src="./images/img_4.jpg" alt="배경화면"/>
    <img data-src="./images/img_5.jpg" alt="배경화면"/>
    <img data-src="./images/img_6.jpg" alt="배경화면"/>
</body>
</html>

⛳결론

img tag loading="lazy" 속성을 활용한 이미지 지연 로딩은 간단하게 사용할 수 있지만 세세하게 컨트롤을 할 수 없다고 느껴졌으며 Intersection Observer API(교차 관찰자 API) 는 타겟 요소가 뷰포트와 교차했을 때 다양하고 세세한 컨트롤이 가능하다는 점이 정말 좋았다.

profile
잘 하고 싶다.

0개의 댓글