이 글은 아래 원문을 번역한 글로 의역이 있을 수 있습니다. 정확한 의미를 파악하고 싶으신 분은 원문을 참고해주시기 바랍니다.
원문: https://css-tricks.com/the-complete-guide-to-lazy-loading-images/
저작권 정보: https://css-tricks.com
※ https://front-end-news.tistory.com/entry/The-Complete-Guide-to-Lazy-Loading-Images-1-%ED%95%9C%EA%B8%80?category=980446 에 이어 번역한 글 입니다.
4장: CSS 배경 이미지 Lazy 로딩
아래는 CSS 의 일반적인 배경 이미지 입니다.
.my-class { background-image: url('/path/to/some/image.jpg');/* more styles */ }
CSS 배경 이미지는 이미지 태그 처럼 간단하지 않습니다. 그것들을 로드하려면 브라우저는 CSSOM 트리 뿐 아니라 DOM 트리도 생성해서 CSS 스타일을 현재 문서의 DOM 노드에 적용해야 하는지 여부를 결정해야 합니다. 배경 이미지를 지정하는 CSS 규칙이 문서의 요소(element) 에 적용되지 않으면 브라우저는 배경 이미지를 로드하지 않습니다. CSS 규칙을 현재 문서의 element 에 적용할 수 있을 때 브라우저는 이미지를 로드합니다.
네? 처음에는 복잡해 보이지만, 이 동작은 이미지 lazy 로딩 기술의 기본 동작과 같습니다. 간단히 말해서, 우리는 element에 background-image CSS 속성이 적용되지 않도록 브라우저를 속일 겁니다. 그 element 가 뷰포트에 올라올 때 까지요.
자 여기 CSS 배경 이미지 lazy 로드가 어떻게 동작하는지 보여주는 예시가 있습니다.
https://codepen.io/imagekit_io/pen/RBXVrW
여기서 주의할 점은 Lazy 로딩의 자바스크립트 코드는 여전히 (이전과) 똑같다는 것입니다. 여전히 이벤트 리스너에 대한 폴백과 함께 아직 Intersection Observer API 메서드를 사용하고 있습니다. "트릭" 은 CSS 안에 있습니다.
우린 background-image 속성이 적용되어 있고 ID 가 bg-image 인 element 를 가지고 있습니다. 하지만, 우리가 그 element 에 lazy 클래스를 추가하면, 우린 CSS 의 none 속성 으로 값을 세팅함으로써 원래의 background-image 속성을 덮어 쓸 수 있습니다.
ID와 클래스를 가진 element 는 ID만 사용하는 것보다 CSS에서 우선순위가 높기 때문에 브라우저는 그 속성을 적용합니다. background-image: none 이 element 에 적용 됩니다.아래로 스크롤하면 Intersection Observer API (또는 선택한 방식에 따라 이벤트 리스너)는 이미지가 뷰포트에 있는 것을 검출하여 element 에서 lazy클래스를 제거 합니다. 이것에 의해, 해당하는 CSS가 변경되어 실제의 CSS가 적용됩니다. background-image요소에 대한 속성, 배경 이미지의 로드를 트리거합니다.
5장: Lazy 로딩으로 더 나은 사용자 경험 만들기
Lazy 로딩은 훌륭한 성능 효과를 제공합니다. 한 페이지에 수백 개의 제품 이미지를 로드하는 전자상거래 회사에서는 느린 로딩으로 초기 페이지 로드를 대폭 개선하고 대역폭 소비를 줄일 수 있습니다.
그러나 많은 기업은 뛰어난 사용자 경험을 제공하는 데 역행한다고 생각하기 때문에 Lazy 로드를 선택하지 않습니다. (즉, 초기 플레이스 홀더가 보기 좋지 않거나, 로딩 시간이 느림 등의 이유로요. )
[역자 주: 여기서 플레이스 홀더란, 이미지가 로딩 완료되기 전에 보이는 화면을 말한다.)
이 섹션에서는 이미지들의 lazy 로딩으로 인해 발생하는 사용자 경험과 관련된 몇가지 문제들을 해결 해볼 것 입니다.
팁 1. 올바른 Placeholder 사용
placeholder 는 실제 이미지가 로드될 때까지 컨테이너에 표시됩니다.일반적으로 개발자는 이미지의 경우 단색의 플레이스 홀더를 사용하거나 특정 하나의 이미지를 플레이스 홀더로 사용합니다.
지금까지 살펴본 예에서도 비슷한 방식이 사용되었습니다. : 밝은 회색 바탕의 상자를 보여줬죠. 하지만, 우리는 보다 쾌적한 사용자 경험을 제공할 수 있습니다. 다음은 이미지에 더 나은 플레이스 홀더 를 사용하는 두 가지 예시 입니다.
주요(Dominant) 색상 placeholder
이미지 플레이스 홀더에 고정 색상을 사용하는 대신 원본 이미지에서 눈에 띄는 색상을 찾아 플레이스 홀더로 사용합니다.이 기술은 구글의 이미지 검색 결과뿐만 아니라 핀터레스트의 그리드 디자인에서도 오랫동안 사용되어 왔습니다.
(https://manu.ninja/dominant-colors-for-lazy-loading-images/)
복잡한 것처럼 보일 수 있지만 Manuel Wieser는 이미지를 1×1픽셀로 축소하고 플레이스 홀더 크기로 확대함으로써 이를 실현하는 우아한 솔루션을 가지고 있습니다. 이것은 대략적인 근사치이지만, 주요 단일 색상을 얻을 수 있는 간단한 방법입니다. ImageKit를 사용하면 아래 그림과 같이 ImageKit의 체인 변환을 사용하여 주요 색상 플레이스 홀더를 얻을 수 있습니다.
<!-- Original image at 400x300 -->
<img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300" alt="original image">
<!-- Dominant color image with same dimensions -->
<img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-1,h-1:w-400,h-300" alt="dominant color placeholder">
플레이스 홀더 이미지는 원래 이미지 12700바이트(19배)에 비해 크기가 661바이트에 불과합니다.또, 플레이스 홀더에서 실제 이미지로 nicer 한 전환도 할 수 있습니다.
다음은 이 효과가 사용자에게 어떻게 작용하는지 보여 주는 비디오입니다.
https://www.youtube.com/watch?v=wJEoRz3P3EU
https://codepen.io/imagekit_io/pen/WgvmZj
저화질의이미지 플레이스 홀더 (LQIP)
우린 위의 아이디어를 우세한 색상 플레이스 홀더에 사용하는 것으로 확장 시킬 수도 있습니다. 단색을 사용하는 대신, 매우 저화질을 사용하는 거죠. 원본 이미지의 블러처리된 버전을 플레이스 홀더로 사용하는 겁니다. 그것은 보기 괜찮을 뿐 아니라, 사용자에게 실제 이미지가 어떻게 생겼을 지에 대한 힌트와, 이미지가 로딩 되고 있다는 인식을 줄 수도 있습니다.
이것은 인식된 로딩 경험을 개선하는데 매우 유용합니다. 이 기술은 Facebook 과 Medium 같은 곳에서 활용 되고 있습니다.
ImageKit 를 사용한 LQIP 이미지 URL 예시 입니다.
<!-- Original image at 400x300 -->
<img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300" alt="original image">
<!-- Low quality image placeholder with same dimensions -->
<img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300,bl-30,q-50" alt="dominant color placeholder">
LQIP의 크기는 1300바이트로, 여전히 원본 이미지보다 거의 10배 작고 다른 플레이스 홀더 기술에 비해 시각적 경험 측면에서 상당히 개선 되었습니다.
여기 이 효과가 어떻게 사용자에게 동작하는지 보여주는 비디오 입니다.
https://www.youtube.com/watch?v=BXoNamwkqi0
https://codepen.io/imagekit_io/pen/EpqXGW
우세 색상 혹은 LQIP 플레이스 홀더를 사용하면 플레이스 홀더에서 실제 이미지로의 전환이 더 자연스러워집니다. 또한 사용자에게 플레이스 홀더 대신 무엇이 올 것인지 알려 줄수도 있어서, 로딩 중임을 더 잘 인식할 수 있습니다.
팁 2: 이미지 로드를 위한 버퍼 시간 추가
이미지 로드를 트리거하는 다양한 방법에 대해 설명할 때, 우린이미지가 뷰포트에 들어가는 시점을 확인했습니다. 즉, 이미지 플레이스 홀더의 위쪽 가장자리가 뷰포트의 아래쪽 가장자리와 일치할 때 이미지 로드가 트리거됩니다.
문제는 사용자가 페이지를 매우 빠르게 스크롤하여 이미지를 로드하고 화면에 표시하는 데 시간이 걸린다는 것입니다. 쓰로틀링과 함께 부하가 더 지연될 수 있으므로 사용자는 이미지가 표시될 때까지 몇 밀리초 더 기다려야 할 수 있습니다. 사용자 경험에는 적합하지 않습니다!
성능을 위한 Intersection Observer API 와 원활한 전환을 위한 LQIP를 사용해서 우수한 사용자 경험을 제공할 수 있지만, 뷰포트에 들어갈 때 이미지가 항상 완전히 로드되도록 하기 위해 사용할 수 있는 또 다른 간단한 방법이 있습니다. 바로 이미지의 트리거 지점에 마진을 도입하는 것입니다.
뷰포트에 들어갈 때 이미지를 로드하는 대신 뷰포트에 들어가기 전에 예를 들어 500px일 때 이미지를 로드합니다.그러면 로드 트리거와 뷰포트의 실제 항목 사이에 이미지가 로드될 수 있는 추가 시간이 제공됩니다.
Intersection Observer API를 사용하면 root파라미터와 함께 rootMargin 매개 변수(표준 CSS 마진 규칙처럼 동작)를 사용하여 교차로를 찾는 것으로 간주되는 유효 경계 상자를 늘립니다.이벤트 리스너 방식에서는 이미지 엣지와 뷰포트 엣지 간의 차이가 0인지 확인하는 대신 양수를 사용하여 임계값을 추가할 수 있습니다.
https://codepen.io/imagekit_io/pen/gdbYwV
다음 스크린캐스트를 자세히 보면 세 번째 이미지가 표시되었을 때 시퀀스의 다섯 번째 이미지가 로드된다는 것을 알 수 있습니다.마찬가지로 네 번째 이미지가 표시되었을 때 여섯 번째 이미지가 로드되는 등 계속됩니다.이렇게 하면 이미지가 완전히 로드될 때까지 충분한 시간을 두고 대부분의 경우 플레이스 홀더를 볼 수 없습니다.
https://www.youtube.com/watch?v=Zb65sdby7NI
이 모든 예에서 세 번째 이미지는 미리 눈치채지 못한 경우입니다. (image3.jpg)는 뷰포트 외부에 있는 경우에도 항상 사전에 로드됩니다.이 작업도 같은 원리에 따라 수행되었습니다.즉, 보다 나은 사용자 경험을 위해 문턱값까지 정확하게 로드하는 것이 아니라 약간 미리 로드하는 것입니다.
팁 3: 콘텐츠 리플로우 회피
이것은 또 하나의 사소한 점이며, 해결되면 좋은 사용자 경험을 유지하는 데 도움이 될 수 있습니다.
이미지가 없는 경우 브라우저는 이미지가 차지하는 크기를 알 수 없습니다.또한 CSS를 사용하여 지정하지 않으면 동봉된 컨테이너는 치수가 없으며, 즉 0x0 픽셀로 읽힙니다.
이미지가 로드되면 브라우저는 이미지를 화면에 드롭하고 콘텐츠에 맞게 리플로우합니다.레이아웃이 갑자기 변경되면 다른 요소가 이동하며 이를 콘텐츠 리플로우 또는 이동이라고 합니다.Michael Scharnagl 은 이것이 어떻게 불쾌한 사용자 경험을 만들어 내는지에 대해 자세히 설명합니다.
브라우저가 이미지 컨테이너를 알려진 높이 및 너비로 그릴 수 있도록 둘러싸인 컨테이너의 높이 및/또는 너비를 지정하여 이 문제를 방지할 수 있습니다.나중에 이미지가 로드될 때 용기 크기가 이미 지정되어 있고 이미지가 해당 크기에 완벽하게 맞기 때문에 해당 용기 주변의 나머지 컨텐츠는 이동하지 않습니다.
팁 4: 모든 이미지에 대해서 Lazy 로딩 하는 것은 피하자
모든 경우에 이미지 로드를 늦추는 것이 항상 좋다고 생각하는 것은 매우 매력적이기 때문에, 이것은 개발자들이 자주 저지르는 실수입니다.하지만, 인생이 그런 것처럼, 좋은 것도 너무 지나치면 안됩니다. (과유불급...) Lazy 로딩은 초기 페이지 로드를 줄일 수 있지만, 만약 지연되어서는 안되는 일부 이미지가 있을 경우에 좋지 않은 사용자 경험을 줄 수 있습니다.
몇 가지 일반적인 원칙에 따라 어떤 이미지를 Lazy 로딩을 해야 하는지 구분 할 수 있습니다.예를 들어 뷰포트 또는 웹 페이지 시작 부분에 표시되는 이미지는 Lazy 로딩이 되어서는 안 됩니다.이는 사용자가 처음 페이지를 열 때 볼 수 있는 모든 헤더 이미지, 마케팅 배너, 로고 또는 실제 모든 항목에 적용됩니다.또, 모바일 디바이스와 데스크탑 디바이스의 화면 사이즈가 다르기 때문에, 최초로 화면에 표시되는 이미지의 수가 다릅니다.사용 중인 디바이스를 고려하여 어떤 리소스를 먼저 로드하고 어떤 리소스를 느리게 로드할지 결정해야 합니다.
또 다른 예로는 초기 부하에서 뷰포트에서 약간 벗어난 이미지라도 지연 로딩해서는 안 됩니다.이것은 위에서 설명한 원칙에 따라 약간 미리 로드합니다.예를 들어 뷰포트 하단에서 500px 또는 스크롤을 한 번 사용하여 이미지를 미리 로드할 수도 있습니다.
또 하나의 예는 페이지가 짧은 경우입니다. 스크롤 한 개 또는 스크롤 두 개일 수도 있고 뷰포트 외부에 이미지가 5개 미만일 수도 있습니다. 이 경우 Lazy 로딩을 생략해도 해도 될 수 있습니다. 퍼포먼스 면에서는 사용자에게 큰 이점이 없습니다.게다가 Lazy 로딩을 가능하게 하기 위해 페이지에 로드하는 추가 JavaScript는 이로 인해 얻을 수 있는 잠재적인 이점을 상쇄합니다.
5장: 느린 로딩의 JavaScript 의존성
느린 로딩에 대한 전체 개념은 사용자의 브라우저에서 활성화되고 사용 가능한 JavaScript에 의존합니다.사용자의 대부분은 JavaScript를 유효하게 하고 있습니다만, 유효하지 않은 경우의 계획을 세우는 것이 중요합니다.
사용자에게 이미지가 로드되지 않는 이유를 알려주는 메시지를 표시하고 최신 브라우저를 사용하거나 JavaScript를 사용하도록 권장할 수 있습니다.
또 다른 루트는,noscript태그입니다. 하지만 이 접근법에는 몇 가지 고차(gotcha)가 있습니다.스택 오버플로우 상의 이 질문 스레드는 이러한 문제에 대처하는 데 매우 효과적이며, 이 일련의 사용자에게 권장되는 읽을거리입니다.
6장: Lazy 로딩에 널리 사용되는 JavaScript 라이브러리
환경 및 구현 세부 사항은 브라우저 및 디바이스에 따라 다를 수 있으므로 처음부터 회전 속도를 높이는 것이 아니라 로딩이 느리다는 테스트를 거친 라이브러리를 고려해 보는 것이 좋습니다.
다음은 최소한의 노력으로 느린 로드를 구현할 수 있는 널리 사용되는 라이브러리 및 플랫폼별 플러그인 목록입니다.
- 또 다른 Lazy 로더:이것은 거의 모든 HTML 요소에 매우 적합합니다만, 유감스럽게도 CSS의 배경 이미지에서는 동작하지 않습니다. 이 라이브러리는 Intersection Observer API를 사용하며 아직 지원하지 않는 브라우저의 경우 이벤트 기반 느린 로딩으로 돌아갑니다. 좋은 소식은 IE를 버전 11로 다시 지원한다는 것입니다.
- 라지사이즈:이 라이브러리는 매우 인기 있으며 다양한 기능을 갖추고 있습니다. 반응성 이미지 srcset 과 sizes 속성에 대한 지원을 포함하고 Intersection Observer API 없이도 우수한 성능을 제공합니다.
- WordPress A3 레이지 로드: WordPress 플러그인은 로딩이 느리지만, 이 플러그인은 JavaScript를 사용할 수 없는 경우의 폴백을 포함한 강력한 기능을 갖추고 있습니다.
- jQuery Lazy: jQuery 구현을 사용하는 단순한 라이브러리입니다.
- WeltPixel 레이지 로딩 기능 강화: Magento 2 확장자
- Magento 레이지 이미지 로더: 1.x의 다른 Magento 확장자.
- Lazy Image 플러그인 쇼핑(유료): Shopify 사이트에서 Lazy 로딩을 활성화합니다.
7장: Lazy 로드 테스트
Lazy 로딩을 구현하면 의도한 대로 작동하는지 확인할 수 있습니다.가장 간단한 방법은 브라우저에서 개발자 도구를 여는 것입니다.
여기서부터 [Network]> [ Images ]으로 이동합니다.페이지를 처음 새로 고치면 목록에는 로드된 이미지만 표시됩니다.
그런 다음 페이지 아래로 스크롤을 시작하면 다른 이미지 로드 요청이 트리거되고 로드됩니다.또한 이 뷰의 폭포 열에서 이미지 로드 타이밍을 확인할 수 있습니다.이미지 로드의 문제가 있는 경우 또는 이미지 로드를 트리거하는 데 문제가 있는 경우 이를 식별하는 데 도움이 됩니다.
다른 방법은 변경 사항을 구현한 후 페이지에서 Google Chrome Lighthouse 감사 보고서를 실행하고 "오프스크린 이미지 섹션" 에서 제안 사항을 찾는 것입니다.
결론
이미지 Lazy 로딩에 대해 많은 내용을 다루었습니다! Lazy 로딩 - 만약 잘 구현된다면 말이죠- 은 사이트 성능에 큰 이점을 줄 뿐 아니라, 불필요한 리소스를 사전에 미룰 수 있기 때문에 전체적인 페이지 크기 및 전송 비용을 절약 할 수 있습니다.
자, 뭘 망설이시나요? 지금 바로 이미지 Lazy 로딩을 시작하세요! 또, 이 조작의 원리에 대해 조금 더 알고 싶은 경우는, 다음의 인포그래픽의 카피를 참고 해주세요.