지연 로딩(Lazy Loading)은 초기 로딩 시간을 줄이고 페이지 로딩 속도를 개선하기 위한 기술로, 리소스들을 실제로 사용하는 시점에 로딩하는 것을 이릅니다. 특히, 이미지 최적화에 가장 많이 사용되는 기법입니다.
Lazy Loading을 사용하면 웹 페이지의 초기 로딩 속도가 개선되어 사용자들이 더 빠르게 페이지를 이용할 수 있습니다. 특히 이미지를 로딩하는데 소요되는 시간을 줄일 수 있어, 사용자들이 빠르게 이미지를 볼 수 있도록 해줍니다. 또한, 페이지에 필요한 리소스들을 미리 로딩하지 않고 필요할 때 로딩하기 때문에, 필요하지 않은 리소스들을 로딩하지 않아서 불필요한 네트워크 트래픽을 줄일 수 있습니다.
하지만, Lazy Loading을 적용할 때는 주의해야 할 점도 있습니다. 예를 들어, 페이지에 반드시 필요한 리소스들은 초기 로딩 시점에 로딩되어야 합니다. 또한, JavaScript를 통해 Lazy Loading을 구현할 때는 JavaScript를 지원하지 않는 브라우저에서는 Lazy Loading이 동작하지 않을 수 있습니다. 이러한 점들을 고려하여 적절하게 Lazy Loading을 적용하면, 웹 페이지의 성능을 개선할 수 있습니다.
가장 일반적으로 사용되어지는 방식입니다.
지연 로딩을 적용시킬 요소를 감지하고 이벤트를 발생시키기 위한 트리거를 class에 지정합니다.
이미지 URL을 src
속성이 아닌, data-src
에 할당합니다. <img>
태그의 src가 비어있기 때문에 웹 페이지에 접근했을 때 브라우저는 해당 이미지를 로딩하지 않습니다.
<img>
태그가 뷰포트에 들어온 경우 (즉, 사용자에게 보여지고 있는 경우)를 감지해서 커스텀 속성 data-src
에 들어간 이미지 URL을 <img>
태그의 src에 넣어주면, 실제 사용되는 시점에서 이미지를 로딩할 수 있습니다.
<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는 브라우저 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 - 요소의 가시성 관찰
#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 클래스를 삭제하는 것으로 구현할 수 있습니다.
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