지연 로드 권장사항

이미지 및 동영상 지연 로드는 긍정적이고 측정 가능한 성능 이점이 있지만 가볍게 여겨서는 안 되는 작업입니다. 잘못하면 의도치 않은 결과가 발생할 수 있습니다. 따라서 다음 사항을 염두에 두는 것이 중요합니다.

스크롤 없이 볼 수 있는 부분 주의하기

JavaScript로 페이지의 모든 미디어 리소스를 지연 로드하고 싶을 수 있지만 이러한 유혹을 참아야 합니다. 스크롤 없이 볼 수 있는 부분에 있는 부분은 지연 로드하면 안 됩니다. 이러한 리소스는 중요한 애셋으로 간주되어야 하므로 정상적으로 로드되어야 합니다.

지연 로드는 스크립트가 로드를 마치고 실행을 시작할 때 DOM이 상호작용할 수 있을 때까지 리소스 로드를 지연합니다. 스크롤해야 볼 수 있는 부분의 이미지에는 문제가 없지만 스크롤 없이 볼 수 있는 부분의 중요한 리소스는 최대한 빨리 표시되도록 표준 <img> 요소를 사용하여 로드해야 합니다.

물론 요즘에는 다양한 크기의 여러 화면에서 웹사이트를 볼 때 어느 부분에서 접점이 있는지가 그다지 명확하지 않습니다. 노트북에서는 스크롤 없이 볼 수 있는 부분에 있는 것이 휴대기기에서는 아래에 배치될 수 있습니다. 모든 상황에서 이 문제를 최적으로 해결하기 위한 완벽한 조언은 없습니다. 페이지의 중요한 애셋 인벤토리를 작성하고 이러한 이미지를 일반적인 방식으로 로드해야 합니다.

또한 지연 로드를 트리거하는 임계값으로 접힘 선을 너무 엄격하게 설정하지 않는 것이 좋습니다. 사용자가 표시 영역으로 스크롤하기 한참 전에 이미지가 로드되기 시작하도록 스크롤해야 볼 수 있는 부분 아래에서 어느 정도 떨어진 곳에 버퍼 영역을 설정하는 것이 더 이상적일 수 있습니다. 예를 들어 Intersection Observer API를 사용하면 새 IntersectionObserver 인스턴스를 만들 때 옵션 객체에 rootMargin 속성을 지정할 수 있습니다. 이렇게 하면 요소에 버퍼를 효과적으로 제공하여 요소가 표시 영역에 도달하기 전에 지연 로드 동작을 트리거합니다.

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

rootMargin 값이 CSS margin 속성에 지정하는 값과 비슷하다면 그렇기 때문입니다. 이 경우 관찰된 요소의 하단 여백 (기본적으로 브라우저 표시 영역이지만 root 속성을 사용하여 특정 요소로 변경할 수 있음)이 256픽셀로 확장됩니다. 즉, 이미지 요소가 표시 영역에서 256픽셀 이내에 있으면 콜백 함수가 실행되고 사용자가 실제로 보기 전에 이미지가 로드되기 시작합니다.

Intersection Observe을 지원하지 않는 브라우저에서 동일한 효과를 얻으려면 스크롤 이벤트 처리 코드를 사용하고 getBoundingClientRect 검사를 조정하여 버퍼를 포함합니다.

레이아웃 이동 및 자리표시자

자리표시자를 사용하지 않으면 미디어 지연 로드로 인해 레이아웃이 이동될 수 있습니다. 이러한 변경사항은 사용자를 혼란스럽게 할 수 있으며 시스템 리소스를 사용하고 버벅거림을 유발하는 비용이 많이 드는 DOM 레이아웃 작업을 트리거합니다. 최소한 타겟 이미지와 동일한 크기를 차지하는 단색 자리표시자를 사용하거나 로드되기 전에 미디어 항목의 콘텐츠를 알려주는 LQIP 또는 SQIP와 같은 기법을 사용하는 것이 좋습니다.

<img> 태그의 경우 src는 속성이 최종 이미지 URL로 업데이트될 때까지 자리표시자를 처음에 가리켜야 합니다. <video> 요소에 poster 속성을 사용하여 자리표시자 이미지를 가리킵니다. 또한 <img><video> 태그 모두에 widthheight 속성을 사용합니다. 이렇게 하면 자리표시자에서 최종 이미지로 전환해도 미디어가 로드될 때 요소의 렌더링된 크기가 변경되지 않습니다.

이미지 디코딩 지연

자바스크립트에서 대용량 이미지를 로드하고 DOM에 드롭하면 기본 스레드가 묶여 디코딩이 실행되는 동안 사용자 인터페이스가 잠시 응답하지 않을 수 있습니다. DOM에 삽입하기 전에 decode 메서드를 사용하여 이미지를 비동기식으로 디코딩하면 이러한 종류의 버벅거림을 줄일 수 있지만 주의하세요. 아직 모든 곳에서 사용할 수 없으며 지연 로드 로직이 더 복잡해집니다. 사용하려면 카드를 확인해야 합니다. 다음은 Image.decode()를 대체와 함께 사용하는 방법을 보여줍니다.

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

이 CodePen 링크에서 이 예와 유사한 코드를 실제로 확인합니다. 대부분의 이미지가 상당히 작다면 큰 효과를 볼 수 없지만 큰 이미지를 지연 로드하고 DOM에 삽입할 때 발생하는 버벅거림을 줄이는 데는 도움이 됩니다.

콘텐츠가 로드되지 않을 때

때때로 미디어 리소스가 여러 가지 이유로 로드되지 않고 오류가 발생하기도 합니다. 언제 이런 일이 발생할 수 있나요? 경우에 따라 다르지만, 한 가지 가상의 시나리오가 있습니다. 짧은 기간 (예: 5분) 동안 HTML 캐싱 정책을 사용했는데 사용자가 사이트를 방문하거나 사용자가 오랜 시간 (예: 몇 시간) 오래된 탭을 열어 둔 후 다시 돌아와 콘텐츠를 읽는 경우입니다. 이 프로세스의 특정 시점에서 재배포가 발생합니다. 배포 중에 이미지 리소스의 이름이 해시 기반 버전 관리로 인해 변경되거나 완전히 삭제됩니다. 사용자가 이미지를 지연 로드할 때는 리소스를 사용할 수 없으므로 실패합니다.

비교적 드물게 발생하지만 지연 로드가 실패할 경우 백업 계획을 마련하는 것이 좋습니다. 이미지의 경우 이러한 솔루션은 다음과 같을 수 있습니다.

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

오류 발생 시 취할 조치는 애플리케이션에 따라 다릅니다. 예를 들어 이미지 자리표시자 영역을 사용자가 이미지를 다시 로드하려고 할 수 있는 버튼으로 대체하거나 이미지 자리표시자 영역에 오류 메시지를 표시할 수 있습니다.

다른 시나리오도 발생할 수 있습니다. 어떤 작업을 하든 오류가 발생했을 때 사용자에게 알림을 보내고 문제가 발생할 경우 취할 조치를 제공하는 것이 좋습니다.

JavaScript 사용 가능 여부

JavaScript를 항상 사용할 수 있다고 가정해서는 안 됩니다. 이미지를 지연 로드하려는 경우 JavaScript를 사용할 수 없는 경우 이미지를 표시하는 <noscript> 마크업을 제공하는 것이 좋습니다. 가능한 가장 간단한 대체 예시로는 JavaScript가 사용 중지된 경우 <noscript> 요소를 사용하여 이미지를 제공하는 것이 있습니다.

나는 이미지입니다!

JavaScript가 사용 중지되어 있으면 자리표시자 이미지와 <noscript> 요소에 포함된 이미지가 모두 사용자에게 표시됩니다. 이 문제를 해결하려면 다음과 같이 <html> 태그에 no-js 클래스를 배치합니다.

<html class="no-js">

그런 다음 JavaScript가 사용 설정된 경우 <html> 요소에서 no-js 클래스를 삭제하는 <link> 태그를 통해 스타일시트가 요청되기 전에 <head>에 인라인 스크립트 한 줄을 배치합니다.

<script>document.documentElement.classList.remove("no-js");</script>

마지막으로, JavaScript를 사용할 수 없는 경우 지연 클래스 요소를 숨기는 CSS를 사용합니다.

.no-js .lazy {
  display: none;
}

이렇게 해도 자리표시자 이미지가 로드되지 않는 것은 아니지만 결과는 더 바람직합니다. JavaScript를 사용 중지한 사용자는 자리표시자 이미지보다 더 나은 정보를 얻을 수 있습니다. 이는 자리표시자보다 낫고 의미 있는 이미지 콘텐츠가 전혀 없습니다.