초기 로딩 시간을 단축해주는 Image Lazy Loading 기법
현재 화면에 보여지지 않는 이미지들은 lazy loading 처리를 통해 웹 페이지 초기의 로딩 시간을 단축하여 웹 성능을 향상 시킬 수 있다. image lazy loading 기법은 무엇인지, 그리고 해당 기법을 IntersectionObserver API를 사용한 예시를 보면서 알아보자.
Image Lazy Loading이란?
- 페이지 안에 있는 실제 이미지들이 실제로 화면에 보여질 필요가 있을 때 로딩을 하게 만드는 기법
- 웹 페이지 내에서 바로 로딩을 하지 않고 로딩 시점을 뒤로 미룬다
영어 단어 중 'lazy'는 '가능한 길게 일을 미루는 행위'란 의미에 기반한다.
lazy loading을 다루는 방식은 페이지 내의 거의 모든 리소스에도 적용할 수 있다. 예를 들어, SPA 내에서 JS 파일이 당장 필요하지 않으면 초기에 로드해서 가져오지 않는 것이 좋다. 이처럼 이미지도 당장은 불러오지 않다가, 보여져야 할 때 로딩을 하는 방식이다.
그래서 무엇을 얻을 수 있을까?
image lazy loading은 페이지 내에서 당장은 필요하지 않은 이미지들의 로딩 시점을 뒤로 미루는 것이다. 뷰포트에서 보여지지 않는 이미지들은 스크롤 등으로 실제로 이미지가 보여지는 시점이 올 때 로딩이 된다. 만약 스크롤 등의 동작을 하지 않는다면 보여지지 않은 이미지는 절대 로딩이 되지 않는다.
이러한 점은 2가지를 기대할 수 있다.
1. 성능 향상
페이지의 초기 로딩 시 필요한 이미지의 수를 줄일 수 있다. 이렇게 리소스 요청을 줄이는 것은 다운로드 용량을 줄이는 것이며, 이는 사용자가 사용할 수 있는 제한된 네트워크 대역폭의 경쟁을 줄이는 것을 의미한다. 또한 다른 리소스들을 더 빠르게 처리할 수 있게 도와줄 수 있다. 따라서 lazy loading을 쓰지 않는 것에 비해 사용자가 페이지를 더 빠르게 볼 수 있도록 돕는다.
2. 비용 감소
두 번째로 통신 비용 관점의 장점이 있다. 이미지 전달 또는 다른 리소스를 전달한다는 것은 주로 전송 바이트 수에 기반하여 청구된다.
image lazy loading은 이미지가 보여지지 않으면 절대 로딩하지 않기 때문에 페이지 내에서 전달할 총 바이트 용량을 줄일 수 있다. 특히나 페이지를 이탈하거나 페이지의 최상단에만 서비스를 이용하는 사용자에게 효과적이다. 이처럼 네트워크로부터 전송될 바이트의 감소는 전송 비용을 줄일 수 있다.
적용할 수 있는 이미지는?
lazy loading의 기본적인 방법은 간단하다. 지금 당장 필요하지 않은 모든 요소들의 로딩을 잠시 지연하는 것이다. 따라서 사용자 화면에 보여지지 않는 이미지들은 모두 로딩을 지연시킬 수 있다.
사용자가 페이지에서 스크롤을 아래로 내림으로써, 이미지의 placeholder는 뷰포트(웹 페이지 내 보여지는 부분)에 다가오게 된다. 뷰포트에 보여지게 되면 이미지를 로딩하도록 트리거를 일으킨다.
image lazy loading에 도움이 되는 사이트는 다음과 같다.
- Google Lighthouse audit toll
- lazy loading에 어떤 이미지가 적합한지 알 수 있다.
- 페이지 초기 로딩 시 얼마나 바이트 용량을 줄일 수 있는지 알 수 있다.
- ImageKit's website analyzer
- lazy loading 사용 여부를 확인 할 수 있다.
- 페이지 내에서 크리티컬한 이미지 관련 최적화 용도로 사용할 수 있다.
좋은 퍼포먼스 뿐만 아니라 서비스 사용성에서도 효과적인 image lazy loading을 적용해보자.
IntersectionObserver API를 사용한 Image Lazy Loading
image lazy loading을 다루는 여러 가지 기술이 있다. 이 글에선 그 중 IntersectionObserver API를 중점으로 다룰 예정이다. 그 외의 방법들은 웹 성능 최적화를 위한 Image Lazy Loading 기법 글에 다양한 예시가 나와있다.
<img> 태그를 이용한 일반적인 방법
lazy loading 이미지들은 두 단계로 나눌 수 있다.
우선 첫 번째로 이미지 로딩을 사전에 막아야 한다. 일반적으로 브라우저는 <img> 태그를 이용해서 이미지를 로드하기 위해 태그 내 src 속성을 사용한다. HTML 내 첫 번째 이미지든 1000번째 이미지든, 또는 뷰포트 밖에 있든 상관없이 만약 브라우저가 src 속성을 갖는다면 이미지를 무조건 로드한다.
따라서 이와 같은 이미지들의 로딩을 지연시키기 위해 src 속성 대신 다른 속성에 이미지 URL을 넣어야 한다. 그 방법은 다음과 같다.
<img data-src="https://onlydev.tistory.com/demo/default-image.jpg" />
위 방식으로 이미지 로드를 사전에 막고 브라우저에게 해당 이미지를 언제 로딩할 것인지 알려주어야 한다. 이를 위해서 해당 이미지가 뷰포트에 들어오자마자 로딩할 수 있도록 확인해야 하는데 이를 IntersectionObserver API를 통해 구현이 가능하다.
IntersectionObserver API는...
이 API는 비교적 쉽게 구현할 수 있고 스크롤 이벤트리스너를 통해 구현하는 것보다 성능도 좋다.
IntersectionObserver API를 사용하여 lazy load를 구현한 예시
lazy load 시킨 이미지들을 로딩시키기 위해 해당 이미지들에 옵저버를 적용한다. 엘리먼트가 뷰포트에 들어간 것을 확인하기 위해 isIntersecting 그리고 intersectionRatio 속성을 사용한다. 또한 확인이 되면 URL을 data-src 속성에서 src 속성으로 옮겨서 브라우저가 이미지를 로드하도록 트리거를 일으킨다. 그 후 해당 이미지는 lazy 클래스를 제거하고 옵저버를 해제한다.
const useLazyLoading = () => {
const imgs = document.querySelectorAll('.lazy');
const observerCallback = (entries, observer) => {
entries.forEach(({ isIntersecting, intersectionRatio, target }) => {
if (isIntersecting && intersectionRatio > 0) {
target.src = target.dataset.src;
target.classList.remove("lazy");
observer.unobserve(target);
}
});
};
const io = new IntersectionObserver(observerCallback);
imgs.forEach((img) => io.observe(img));
};
useLazyLoading();
IntersectionObserver API는 IE를 제외하곤 거의 모든 브라우저에서 지원되고 있다. 해당 API가 지원되지 않는 브라우저에서는 event listener 방식으로 사용하도록 해야 한다.
자바스크립트에 대한 Lazy Loading의 의존성
이러한 방식은 사용자의 브라우저 내에서 자바스크립트 동작에 의존한다. 따라서 자바스크립트가 지원되지 않는 브라우저를 사용하거나 자바스크립트 동작을 허용하지 않도록 설정한 사용자들은 어떻게 해야할까?
사용자에게 최신 브라우저를 이용 또는 자바스크립트를 활성화 하라는 메세지를 띄우거나, 이미지가 왜 로딩되지 않는지 알려줄 수도 있다. 아니면 <noscript> 태그를 사용해서 사용자에게 좋은 사용성을 제공할 수도 있다. 하지만 해당 방식은 몇가지 문제점을 갖고 있다.
해당 문제점에 대한 좋은 해결방법은 여기에서 확인 할 수 있다.
참고
웹 성능 최적화를 위한 Image Lazy Loading 기법 - Hello이뇽
도움 되는 글
Intersection Observer - 요소의 가시성 관찰 - heropy
'Web' 카테고리의 다른 글
IE로 접속 시 알림창(alert) 띄우기 (0) | 2022.04.29 |
---|---|
배포 자동화? CI/CD가 무엇일까? (0) | 2021.12.09 |
CSR과 SSR 이해하기 (2) | 2021.10.15 |
HTTP 이해하기 (0) | 2021.09.13 |
304 Not Modified 이해하기 (0) | 2021.09.09 |