Image Lazy Loading

mechaniccoder·2020년 12월 3일
1
post-thumbnail

오늘은 등 운동을 조지고 자기 전에 lazy loading을 구현하는 2가지 방법을 정리해보려고 합니다. 방법은 아래와 같습니다.

  • scroll event
  • Intersection Observer

먼저 html파일 구조를 확인하세요.

index.html

<div id="app">
	<img
	  src="https://images.unsplash.com/photo-1606822350112-b9e3caea2461?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyfHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  src="https://images.unsplash.com/photo-1606936405812-1bdddbd08fd5?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0fHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  src="https://images.unsplash.com/photo-1606945094026-f93bf0b75ee0?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw3fHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	  data-src=""
	/>
	<img
	  src="https://images.unsplash.com/photo-1606940077503-8cd3365e5cdc?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1fHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606854385394-14d09ac9e14e?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxMXx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606726712298-a9d14f8297a0?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxM3x8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606895213457-36798be25021?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxMnx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606828367227-4239d8229dbd?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxNnx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606922619211-1448e81dd5bf?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyMnx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606847993410-27c7ba6beeb8?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyN3x8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606895125340-0b56a65d52ff?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyNnx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606823605375-455be4b8e84e?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyOHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606838830438-5f380a664a4e?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzM3x8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606840955672-94a03be58496?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzNnx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606838830981-e71375a3744b?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzOHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606846646130-e38ef8be6ae5?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0MHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606838975183-abef02eea03e?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0Mnx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606827729365-a54bc3802682?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0NXx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606835265808-8bac088170d9?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0NHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606838001695-c041b2bfcf0b?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1MHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606879992317-a7e2ee28f976?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1Nnx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
	<img
	  data-src="https://images.unsplash.com/photo-1606825526677-5023c8a074d2?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1OHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60"
	/>
</div>

Scroll Event

window 객체에 스크롤 이벤트를 걸어서 image DOM의 y축 좌표 위치를 추적합니다. 만약, DOM의 y축 거리가 우리가 설정한 거리보다 작아진다면 이미지 src를 할당해주면 됩니다. 말보단 코드겠죠? 아래 코드를 확인해보세요.

index.js

const images = document.querySelectorAll("img");

// scroll event를 활용한 lazy loading
window.addEventListener("scroll", () => {
  images.forEach((image) => {
    const rect = image.getBoundingClientRect();
    if (!image.src && rect.top < window.innerHeight * 1.3) {
      image.src = image.dataset.src;
    }
  });
});

우리가 정한 기준점에 태그가 들어왔을 때 data-src에 넣어 뒀던 이미지 주소를 src 속성에 할당합니다. img 태그는 src 속성에 값을 받으면 이미지를 로딩한답니다.

참고로 images가 유사배열이라서 forEach 메서드를 못 쓸 줄 알았는데 확인해보니 prototype(NodeList)에 forEach 메서드가 있더군요. 😲

Intersection Observer

두 번째 방법은 브라우저가 제공하는 Web API인 IntersectionObserver를 활용하는 것입니다. IntersectionObserver를 모르셨던 분들은 잘 정리된 블로그 포스팅이 있으니 링크 걸어두겠습니다. (갓...)

Intersection Observer - 요소의 가시성 관찰

위에 걸어둔 포스팅을 공부하시고 아래 코드를 보면 이해하기 매우 쉬울겁니다.

const images = document.querySelectorAll("img");

const ioOptions = { rootMargin: "300px" }; // 화면에 나타나기전 미리 로딩을 위해!
const io = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {
    if (entry.intersectionRatio > 0) {
      const target = entry.target;
      if (!target.src) { // 미리 로드된 이미지 태그들을 제외해줍니다.
        target.src = target.dataset.src;
      }
    }
  });
}, ioOptions);
images.forEach((image) => io.observe(image));

정리

오늘은 image lazy loading에 대해 알아봤습니다. 어플리케이션에서 performance를 결정하는 요소 중에 이미지가 차지하는 비율이 약 70%입니다. (어디서 본 것 같은데...) 따라서 이미지 최적화는 유저 경험을 생각했을 때 필수라고 생각합니다. 구현이 쉬워서 금방 익숙해질 것 같네요. 그럼 오늘도 수고했어여ㅎㅎ

profile
세계 최고 수준을 향해 달려가는 개발자입니다.

0개의 댓글