본문 바로가기

성능

The Complete Guide to Lazy Loading Images - 1 (한글)

이 글은 아래 원문을 번역한 글로 의역이 있을 수 있습니다. 정확한 의미를 파악하고 싶으신 분은 원문을 참고해주시기 바랍니다.

 

원문: https://css-tricks.com/the-complete-guide-to-lazy-loading-images/

저작권 정보: https://css-tricks.com

 

Lazy Loading Images – The Complete Guide

Lazy loading images that are not in the viewport improves initial page load performance and user experience. This is an in-depth guide to everything about lazy loading of images including native lazy loading methods.

imagekit.io

※ 두편으로 나눠 번역할 예정 입니다. 참고 바랍니다.

 


 

이미지들은 중요합니다. 홍보용 배너이던, 상품 이미지들이이던 혹은 로고이던, 이미지 없는 웹사이트는 상상하기 힘들죠. 그렇지만 슬프게도, 이미지들은 종종 페이지를 부풀리게 하는 데 가장 큰 기여를 하는 무거운 파일들이기도 합니다. HTTP 아카이브의 이미지들의 상태 리포트에 따르면, 데스크탑에 있는 중간 페이지의 크기는 1511KB 이고 이미지들은 전체의 거의 45%(650KB) 를 차지한다고 합니다.

 

이것은 즉, 단순히 이미지들을 없앨 수 있는 것이 아니라는 거죠. 이미지들은 전반적인 사용자 경험에 있어 너무 중요합니다. 대신, 우리는 웹 페이지들을 그것들과 함께 정말 빨리 로드 시켜야 합니다. 이 가이드에서는, 이미지들이 필요해질 때까지, 로드를 연기해서 웹 페이지를 로드하는데 걸리는 시간을 개선 시키는데 도움이 되는 기술인 이미지 지연 로딩의(lazy loading images) 모든 기능을 다룰 겁니다.

이 포스트는 lazy loading 의 고려 사항들, 툴들, 기술 등등 자세한 주제들을 다루고 있습니다. 하지만, 네이티브 lazy loading 이 시작되기 전에 작성되어서, 구현할 솔루션을 파악할 떼, 네이티즈 lazy loading 을 통합하는 것이 현명할 겁니다.

바로 들어가기 전에, 여기 그 개념을 보여주는 샘플 비디오가 있습니다. 간단히 말하면, 회색 placeholder 박스는 뷰안으로 그것이 스크롤 될 때까지만 렌더링 되고, 뷰에 보이는 시점에, 상자 대신 실제 이미지가 로드 됩니다.

https://www.youtube.com/watch?v=CPmNHj9a0JI&t=5s

 

Chapter1: Lazy 로딩이란?

우리는 종종 “Lazy” 라는 단어를 가능한 한 오랫동안 일을 피하거나 아무것도 하지 않으려는 행동과 연관시킵니다.

비슷하게, lazy 로딩은 필요하지 않은 페이지의 리소스 로딩을 연기 시킵니다. 리소스들을 바로 로딩하는 대신, 나중에 로드 할 수 있게 해줍니다.

Lazy 로딩은 웹과 어플리케이션 개발에서 리소스를 미리 로드하는 대신, 나중에 필요한 시점으로 페이지의 리소스 로드를 연기하는 일련의 기술 입니다. 이런 기술은 성능을 개선하고 디바이스 리소스를 더 잘 활용하며 관련 비용을 줄이는데 도움을 줍니다.

Lazy 로딩 깃ㄹ은 페이지의 거의 모든 리소스에 적용할 수 있습니다. 예를 들어, Javascript 파일도 처음에 로드하지 않는것이 좋다면 보류 될 수 있습니다. 이미지를 다루는 것도 똑같습니다. - 필요할 때 로드 하면 됩니다.

이 가이드에서는 이미지들을 lazy 로딩 시키는 것에만 초점이 맞춰져 있지만, 다른 것들에도 적용시킬 수 있다는 것을 알아두는 것이 좋스니다.

Chapter2: 왜 Lazy 로드 인가?

만약 사용자가 이미지가 있는 페이지의 어떤 지점으로 절대 스크롤 하지 않는다면, 그 사용자는 그 이미지를 절대 보지 못할 겁니다. 그 이미지도 절대 로드가 되지 않을 겁니다. 왜냐면, 필요한 적이 없으니까요.

당신은 아마 이게 어떻게 당신과 사용자 모두에게 이득이 되는지 보이기 시작했을 수도 있습니다. 우리가 lazy 로딩을 함으로서 얻는 두 가지 이점이 있습니다.

 

성능 향상

분명한 이점은 로드도 빨리 되는 더 작은 웹페이기지를 얻는 다는 것이죠. Lazy 로딩은 페이지에 미리 로드해야 하는 이미지들의 수를 줄여 줍니다. 이미지 요청이 적으면 다운로드 할 바이트 수가 줄어들죠. 다운로드할 바이트 수가 적다는 것은 그 바이트들이 요청이 이뤄진 경우 보다 페이지가 더 빨리 렌더링 된 다는 것을 의미합니다.

이렇게 하면 모든 네트워크의 모든 디바이스에서 나머지 리소스를 훨씬 빠르게 다운로드 하고 처리할 수 있습니다. 따라서 요청에서 렌더링까지의 시간이 줄어들고 페이지도 훨씬 빨리 사용할 수 있습니다. 윈윈이죠!

비용 절감

두 번째 이점은 웹사이트 관리자에게 있습니다. CDN(컨텐츠 전송 네트워크), 웹 서버 또는 스토리지와 같은 클라우드 호스팅 서비스는 전송된 바이트 수 만큼의 비용이 드는 이미지들을 전달합니다. (또는 그런 종류의 어셋들을요) Lazy 로딩 이미지는 사용자자 그것에 도달하지 않는다면 로드 되지 않습니다. 따라서, 당신은 페이지에 전달되는 총 바이트수를 줄이고, 궁극적으로 몇 푼도 절약할 수 있게 됩니다. 페이지에서 바로 이탈하거나, 콘텐츠의 상단 부분만 본 사용자의 경우 특히 그렇죠.

전송 네트워크 또는 서버에서 전송되는 바이트수를 줄이면, 전송 비용이 절감됩니다. 이 부분은 Lazy 로딩에 관해 탐구하면서 더 분명해 질 것 입니다.

얼마나 절약하게 될까요?? 어떤 이미지들이 Lazy 로딩의 후보가 될지 그리고 얼마나 많은 바이트들을 당신이 초시 페이지 로딩시에 절약하게 될지는 Googl Lighthouse audit tool 을 통해 알 수 있습니다. 여기에는 오프 스크린 이미지 전용 섹션이 있습니다. 또한 Image Kit 의 웹사이트 분석기를 이용해서 웹사이트가 페이지의 다른 중요한 이미지 관련 최적화와 별도로 Lazy 로딩을 사용하는지 여부를 식별할 수도 있습니다.

Lazy 로딩은 좋은 성능뿐만 아니라 좋은 사용자 경험을 제공하는데도 중요합니다. 성능과 사용자 경험을 지연 로드와 결합하는 것이 중요하고 어렵기 때문에 이미지를 지연 로드하는 다양한 방법을 살펴본 후 이 가이드 전체에서 이 주제를 계속해서 자세히 다룰 것입니다.

 

Chapter3: 이미지를 위한 Lazy 로딩 기술

페이지에 이미지를 로드하는 두가지 일반적인 방법이 있습니다. <img> 태그와 css background-image 속성 입니다. 먼저 둘 중 더 일반적인 <img> 태그를 살펴본 다음 css 배경 이미지를 살펴 보도록 하죠.

이미지 태그에서의 Lazy 로딩

이미지를 위한 전형적인 HTML 마크업부터 시작하죠

<img src="/path/to/some/image.jpg">

Lazy 로딩을 위한 마크업은 꽤 간단합니다.

1단계는 이미지 로드를 사전에 방지하는 것입니다. 브라우저는 태그의 src 속성을 사용하여 이미지 로드를 트리거합니다. HTML 에서 첫 번째 이미지인지 1,000번째 이미지인지는 중요하지 않습니다. 브라우저가 src 속성을 가져오면 현재 뷰에 있는지 여부에 관계없이 이미지가 다운로드되도록 트리거합니다.

로드를 연기하려면 이미지 URL을 src가 아닌 다른 속성에 넣으면 됩니다. 이미지 태그의 data-src 속성에 이미지 URL을 지정한다고 가정해 보겠습니다. 이제 src가 비어 있고 브라우저가 이미지 로드를 트리거하지 않습니다.

<img data-src="https://ik.imagekit.io/demo/default-image.jpg">

이제 이미지 로드를 방지하고 있으므로 브라우저에 로드할 시기를 알려야 합니다. 그렇지 않으면 (이미지 로드는) 결코 일어나지 않을 것입니다. 이를 위해 이미지(즉, placeholder)가 뷰포트에 들어오자 마자 로드를 트리거하는지 확인합니다.

 

이미지가 뷰포트에 들어오는 시점을 확인하는 두 가지 방법이 있습니다. 작업 코드 샘플과 함께 두 가지를 모두 살펴보겠습니다.

 

방법 1: Javascript 이벤트를 이용해서 이미지 로드를 트리거 하기

이 기법은 브라우저의 scroll, resize 및 orientaionChange 에 대한 이벤트 리스너를 사용합니다. 스크롤 이벤트는 스크롤이 발생할 때 페이지에서 사용자가 어디에 있는지 보고 있기 때문에 매우 명확합니다. resize 와 orientationChange 이벤트도 똑같이 중요합니다. resize 이벤트는 브라우저 창 크기가 변경될 때 발생하는 반면, orientationChange 는 장치가 가로에서 세로로 또는 그 반대로 회전할 때 트리거됩니다.

이 세 가지 이벤트를 사용하여 화면의 변경 사항을 인식하고 화면에 표시되는 이미지 수를 결정하고 그에 따라 로드하도록 트리거할 수 있습니다.

위 이벤트들중 어떤 것이라도 발생하면, 페이지에서 로드가 지연될 모든 이미지를 찾고 이 이미지들 중 현재 뷰포트에 있는 이미지를 확인합니다. 이것은 이미지의 상단(top) 오프셋, 현재 문서의 상단 위치 및 창(window) 높이를 사용하여 수행됩니다. 이미지가 뷰포트에 들어가면 data-src 속성에서 URL을 선택하고 그 url 을 src 속성으로 옮기면 그 결과로 이미지가 로드가 됩니다.

lazy 클래스가 포함된 이미지를 선택하도록 JavaScript에 요청해야 하는 것을 알아두세요. 이미지가 로드되면 더 이상 이벤트를 트리거할 필요가 없으므로 클래스를 제거 할 것입니다. 그리고 모든 이미지가 로드되면 이벤트 리스너도 제거합니다.

스크롤하면 스크롤 이벤트가 여러 번 빠르게 트리거됩니다. 따라서 성능을 위해 스크립트에 lazy 로딩 기능 실행을 조절하는 작은 타임아웃을 추가하여 브라우저의 동일한 스레드에서 실행되는 다른 작업을 차단하지 않습니다.

여기 우리가 이룬 작업의 예시입니다.

https://codepen.io/imagekit_io/pen/MBNwKB

 

Lazy loading images using event handlers - example code

...

codepen.io

 

방법2: Intersection Observer API 를 사용해서 이미지 트리거하기

Intersection Observer API는 비교적 새롭운 것입니다. element 가 뷰포트에 들어갈 때를 감지하고 그 때 어떤 액션을 취하게 해주는 것을 간단하게 만들어 줍니다. 이전 방법에서는 이벤트를 바인딩하고 성능을 염두에 두면서 요소가 뷰포트에 있는지 여부를 계산하는 방법을 구현해야 했습니다. Intersection Observer API는 이런 계산같은 것을 피하고 뛰어난 성능을 제공해서 모든 오버헤드를 제거합니다.

아래는 API를 사용하여 이미지를 lazy 로드하는 예시 입니다. lazy 로드할 모든 이미지에 observer 를 첨부합니다. API가 isIntersecting 속성을 사용하여 element가 뷰포트에 들어간 것을 감지하면 data-src 속성에서 URL을 선택하고 브라우저가 이미지 로드를 트리거할 수 있도록 url 을 src 속성으로 이동 시켜 줍니다. 이 작업이 완료되면 이미지에서 lazy 클래스를 제거하고 해당 이미지에서 observer 도 제거합니다.

 

예시 codpen 링크

 

Lazy loading images using IntersectionObserver - example code

...

codepen.io

두 가지 방법(이벤트 리스너 vs Intersection Observer)에 대한 이미지 로드 시간을 비교하면 Intersection Observer API를 사용하여 이미지가 훨씬 빠르게 로드되고 작업도 더 빨리 트리거된다는 것을 알 수 있습니다. 하지만 사이트에서는 스크롤 하는 도중에도 전혀 느려보이지는 않습니다. 이벤트 리스너를 포함하는 방법에서 성능을 높이기 위해 시간 초과를 추가해야 했습니다. 이는 이미지 로드가 약간의 지연으로 트리거되므로 사용자 경험에 약간 부정적인 영향을 미칩니다.

그러나 모든 새로운 기능과 마찬가지로 Intersection Observer API에 대한 지원은 모든 브라우저에서 사용할 수 있는 것은 아닙니다.

 

(역자 주: 브라우저 지원과 관련한 정보는 Caniuse 를 참고하세요.)

 

따라서 Intersection Observer API가 지원되지 않는 브라우저에서는 이벤트 리스너 방식으로 폴백해야 합니다. 위의 예에서 이것을 고려했습니다.