사용자가 실제로 필요한 콘텐츠만 요청하고 로드하는 방식이다. 페이지가 처음 로드될 때는 필수적인 콘텐츠만 로드하고, 추가적인 콘텐츠를 요청할 때 해당하는 콘텐츠를 로드한다.
예를 들어, 웹 페이지에 많은 이미지가 포함되어 있다면 처음에는 화면에 보이는 이미지만 로드하고, 사용자가 스크롤을 내렸을 때 나머지 이미지를 로드하는 방식이다.
Lazy Loading을 이용하면 필요한 콘텐츠 수를 줄일 수 있다. 다운로드 bytes를 줄이기 때문에 유저가 더 빠르게 페이지를 확인할 수 있게 한다.
콘텐츠가 필요하지 않을 땐 로딩하지 않으므로, 페이지를 모두 확인하지 않거나 상단 서비스만 이용하는 유저에게 특히 효과적이다. 불필요한 로딩이 없어 더 부드러운 전환이 가능하다.
전체 데이터 전송량이 줄어들어 사용자의 대역폭 활용도가 향상되며, 특히 모바일 환경에서 데이터 사용량이 절감되기 때문에 사용자 경험을 개선할 수 있다.
스크롤 이벤트 기반
: 사용자가 페이지를 스크롤할 때 화면에 보이는 영역의 콘텐츠만 로드하는 방식IntersectionObserver API
: 화면에 보이는 영역의 콘텐츠를 API를 활용해 감지하고 로드하는 방식사용자 상호작용 기반
: 사용자의 클릭, 마우스 오버 등의 상호작용을 감지하여 해당 영역의 콘텐츠를 로드하는 방식데이터 속성 활용
: HTML 요소에 data-* 속성을 활용하여 lazy loading 대상 리소스 정보를 저장하는 방식라이브러리 활용
: React의 Suspense, Vue의 Lazy Loading 등 프레임워크에서 제공하는 기능을 활용하는 방식Thumbnail
: 이미지의 크기와 품질을 낮춘 Thumbnail 이미지를 먼저 로드하는 방식캐싱 활용
: 자주 변경되지 않는 리소스들을 브라우저 캐시에 저장하여 재사용하는 방식포맷 최적화
: WebP, AVIF 등의 최신 이미지 포맷을 사용하는 방식<img>
태그에서 이미지를 로드하기 위해, 브라우저는 src
속성을 사용하게 된다.
<img data-src="https://test.com/main.jpg" />
예제는 이미지의 실제 URL을 data-src
에 넣어두고, src
는 비워두었다. 이렇게 하면 브라우저가 페이지를 처음 로드할 때 이미지를 로드하지 않는다. 이후 필요할 때 JavaScript를 사용해 data-src
속성의 값을 src
속성으로 복사하여 이미지를 로드할 수 있다.
우선 이미지 로드를 지연시키기 위해 모든 이미지에 옵저버를 부착시킨다. 엘리먼트가 뷰포트에 들어간 걸 API가 감지했을 때, URL을 data-src
속성에서 src
속성으로 이동시켜서 브라우저가 이미지를 로드하도록 한다. 전부 로드됐을 땐 부착했던 옵저버를 제거한다.
import React, { useEffect, useRef } from 'react';
function Example() {
const targetRef = useRef(null);
const handleIntersection = (entries) => {
entries.forEach((entry) => {
// 타겟 요소가 화면에 보이면 콘솔에 메시지 출력
if (entry.isIntersecting) {
console.log('Target element is visible!');
} else {
console.log('Target element is not visible.');
}
});
};
useEffect(() => {
// 옵저버 생성
const observer = new IntersectionObserver(handleIntersection, {
// 뷰포트 기준 100% 이상 보이면 감지
threshold: 1.0,
});
// 타겟 요소에 옵저버 연결
if (targetRef.current) {
observer.observe(targetRef.current);
}
// 컴포넌트 언마운트 시 옵저버 연결 해제
return () => {
if (targetRef.current) {
observer.unobserve(targetRef.current);
}
};
}, []);
return (
<div>
<div ref={targetRef}>
This is the target element that will be observed.
</div>
</div>
);
}
export default Example;
크롬 브라우저는 lazy loading 기능을 지원한다. <img>
, <iframe>
, <video>
등의 태그에 loading="lazy" 속성을 추가하면 해당 리소스가 필요할 때까지 로드되지 않는다.
<img src="example.jpg" loading="lazy" />
lazy
: 뷰포트에서 일정한 거리에 닿을 때까지 로딩을 지연한다.eager
: 페이지 위치와 상관없이 페이지가 로딩되자마자 로드한다.lazy loading을 사용하면 모든 콘텐츠가 로드되지 않아 보기 좋지 않을 수 있다. 여기 사용자 경험을 개선하기 위한 다양한 방법이 있다.
아래 두 가지 방법은 모두 ImageKit
을 사용해 간단하게 구현할 수 있다.
이미지를 1x1 픽셀로 감소시키고 해당 픽셀의 색으로 placeholder를 채우는 방식이다.
저화질의 흐린 이미지를 placeholder로 사용하여 사용자가 이미지를 추측할 수 있게 한다.
모든 콘텐츠를 lazyloading하지 않도록 주의하자. 로딩은 줄어들 수 있지만, 사용자 경험을 떨어뜨릴 위험이 있다. 웹 페이지가 시작되자마자 보이는 상단(뷰포트) 내의 콘텐츠들은 페이지가 로딩되자마자 보여야 하므로 lazy loading에 적합하지 않다. 디바이스마다 화면 크기가 다르기 때문에, 초기 화면에 보이는 콘텐츠 수가 다르다는 것도 고려해야 한다. 뷰포트에서 조금 떨어진 콘텐츠들도 lazy loading의 대상이 아니다. 한두 번의 스크롤로 확인할 수 있는 내용은 처음부터 로드하는 것이 좋다.