멀티미디어: 이미지

미디어 파일(이미지 + 비디오)은 평균적으로 웹사이트에서 다운로드되는 용량의 약 70% 이상을 차지합니다. 다운로드 성능 측면에서 미디어를 없애거나 파일 크기를 줄이는 것은 어렵지 않습니다. 이 글에서는 웹 성능을 개선하기 위해 이미지와 비디오를 최적화하는 방법을 살펴봅니다.

필요한 사전 지식: 컴퓨터에 대한 기본적인 이해도, 기본적인 소프트웨어 설치, 클라이언트 사이드 웹 기술에 대한 기초 지식
목표: 다양한 이미지 형식과 각 형식이 성능에 미치는 영향, 전체 페이지 로드 시간에 대한 이미지의 영향을 줄이는 법을 배웁니다.

참고: 이 글은 일반적인 원칙과 기술을 포함하여 웹에서의 멀티미디어 전송 최적화를 개략적으로 소개합니다. 더 깊은 내용을 다루는 가이드를 찾으신다면, https://images.guide를 참조하세요.

멀티미디어를 최적화해야 하는 이유

일반적인 웹사이트의 데이터 전송량 중 51%는 이미지가, 25%는 비디오가 차지하기 때문에, 멀티미디어를 능숙하게 다루고 최적화하는 것은 중요하다고 할 수 있습니다.

데이터 사용량은 필수적으로 고려해야 하는 문제입니다. 많은 사람들이 데이터 한도가 있거나 1MB 단위로 요금이 계산되는 종량제 방식의 통신 요금제를 사용하기 때문입니다. 이는 선진국들도 해당되는 문제입니다. 2018년 기준, 영국 인구의 24%가 종량제 요금제를 사용합니다.

메모리 사용량도 중요한 문제입니다. 많은 모바일 기기의 RAM 용량이 크지 않기 때문이죠. 이미지가 다운로드될 때 메모리에 저장되어야 한다는 것을 잊지 마세요.

이미지 전송 최적화

이미지는 데이터 전송량 중 가장 큰 부분을 차지하지만, 이미지 다운로드가 사용자가 인지하는 성능에 영향을 끼치는 정도는 많은 사람들의 생각보다 훨씬 적습니다. 가장 큰 이유는 페이지 내 텍스트가 즉시 다운로드되어 표시되고 사용자들이 이미지가 도착하면서 렌더링되는 것을 볼 수 있기 때문입니다. 하지만 좋은 사용자 경험을 위해선 방문자들이 이미지를 가능한 한 빨리 볼 수 있어야 합니다.

로딩 전략

대부분의 웹사이트에서 가장 큰 개선 사항 중 하나는 방문자의 스크롤 여부와 무관하게 초기 페이지 로드 시 이미지를 모두 다운로드하는 대신, 스크롤을 해야 볼 수 있는 이미지를 지연 로딩하는 것입니다. lazysizes와 같은 많은 JavaScript 라이브러리가 지연된 로딩을 구현하고 있으며, 웹 브라우저 제조사들도 내장 lazyload 속성을 실험적 기능으로 제공하고 있습니다.

이미지를 로딩된 이후에는 이미지 형식 자체를 들여다봐야 합니다.

  • 최적의 파일 형식으로 로딩하고 있나요?
  • 이미지는 잘 압축되었나요?
  • 올바른 크기의 이미지를 로딩하고 있나요?

최적의 파일 형식

어떤 파일 형식이 가장 적합한지는 이미지의 특성에 따라 다릅니다.

참고: 이미지 파일 유형과 형식 가이드에서 이미지 유형에 대한 일반적인 정보를 찾을 수 있습니다.

SVG 형식은 색상이 적고 사실적이지 않은 이미지에 더 적합합니다. SVG 형식을 사용하려면 원본 이미지를 벡터 그래픽 형식으로 쓸 수 있어야 합니다. 만약 원본 이미지가 비트맵 형식으로만 존재한다면 PNG 형식이 대안이 될 수 있습니다. 이런 주제의 유형으로는 로고, 일러스트, 차트, 아이콘 등이 있습니다. (참고: SVG는 아이콘 폰트보다 훨씬 낫습니다!) SVG와 PNG 모두 투명도를 지원합니다.

PNG는 세 가지의 출력 조합을 지정해 저장할 수 있습니다.

  • 24-bit 색상 + 8-bit 투명도 - 가장 정확한 색상과 부드러운 투명도를 제공하는 대신 파일의 크기가 큽니다. 만약 WebP를 선호하는 분이라면 이 조합은 피하고 싶을 것입니다. (아래를 참고하세요.)
  • 8-bit 색상 + 8-bit 투명도 - 255개 이하의 색상과 부드러운 투명도를 제공합니다. 용량은 그렇게 크지 않습니다. 많은 사람이 원할 만한 PNG입니다.
  • 8-bit 색상 + 1-bit 투명도 - 255개 이하의 색상과 단 픽셀당 투명하거나 투명하지 않거나의 단 두 가지 투명도 설정을 제공합니다. 그렇기 때문에 투명한 영역의 테두리가 부드럽지 않고 울퉁불퉁해 보입니다. 용량은 작지만 시각적 정확도가 떨어집니다.

온라인으로 SVGOMG라는 괜찮은 SVG 최적화 서비스를 이용하실 수 있습니다. PNG의 경우 ImageOptim onlineSquoosh가 괜찮습니다.

투명도가 필요하지 않은 '사진 같은' 이미지는 더 넓은 범위의 파일 형식을 선택할 수 있습니다. 안전한 방식을 선호한다면, 잘 압축된 점진적 JPEG이 적합할 것입니다. 점진적 JPEG은 일반적인 JPEG과 다르게 점진적으로 렌더링됩니다 (이름 그대로 말이죠). 사용자는 완전한 해상도의 이미지가 상단에서 하단으로 로딩되거나 모두 다운로드된 이후 렌더링되는 대신 이미지 다운로드가 진행되면서 낮은 해상도에서 높은 해상도로 점점 더 명확해지는 것을 보게 됩니다. 점진적 JPEG 압축방식 중 괜찮은 것으로 MozJPEG이 있는데요, 온라인 이미지 최적화 도구인 Squoosh에서 사용할 수 있습니다. 75% 품질 설정 정도면 괜찮은 결과를 얻을 수 있을 것입니다.

JPEG 대비 압축 성능을 개선한 다른 파일 형식들이 더 있지만, 모든 브라우저에서 쓸 수 있는 것은 아닙니다.

  • WebP - 이미지와 애니메이션 이미지 두 경우 모두 훌륭한 선택입니다. WebP는 PNG, JPEG보다 훨씬 더 높은 압축률과 표현 색상 수, 애니메이션의 프레임 수, 투명도 등을 제공합니다. (단, 점진적 표시 기능은 없습니다). macOS 컴퓨터의 Safari 14 외 모든 주요 브라우저가 지원합니다.

    Note: Safari 14에서의 WebP 지원이 공표되었지만, 여전히 macOS 데스크탑에서는 .webp 이미지가 표시되지 않습니다. 반면 iOS 14에서는 정상적으로 표시됩니다.

  • AVIF - 이미지와 애니메이션 이미지 두 경우 모두 훌륭한 선택으로, 높은 성능의 무료 이미지 형식입니다. (WebP보다 더 효율적이지만, 지원 범위는 넓지 않습니다.) Chrome, Opera, Firefox가 지원합니다. 이전 이미지 형식들을 변환해주는 온라인 AVIF 변환도구를 참고하세요.

  • JPEG2000 - 한때 JPEG의 계승자였으나 지금은 Safari만 지원하고 있습니다. 점진적 표시 기능도 없죠.

JPEG-XR과 JPEG2000의 좁은 지원 범위와 높은 복호화 비용을 고려하면 JPEG의 유일한 경쟁자는 WebP입니다. 그러므로 이미지를 WebP 형식으로도 제공할 수 있습니다. 이를 위해선 <picture> 요소에 <source> 요소를 넣고 type 속성을 적용하면 됩니다.

이 모두가 다소 복잡하거나 소속 팀에게 너무 과한 작업처럼 느껴진다면 이미지 CDN처럼 사용할 수 있는 온라인 서비스들이 있습니다. 이미지를 요청하는 기기 유형과 브라우저에 따라 적절한 이미지 형식을 제공하는 과정을 자동화해주죠. 가장 많이 사용되는 것으로는 CloudinaryImage Engine이 있습니다.

마지막으로, 페이지에 애니메이션 이미지를 넣고 싶을 경우 Safari는 <img><picture> 요소 안에 비디오 파일을 사용할 수 있다는 것을 알아두세요. 다른 모든 최신 브라우저들에서는 이 요소들을 사용해 애니메이션 WebP를 추가할 수 있습니다.

html
<picture>
  <source type="video/mp4" src="giphy.mp4" />
  <source type="image/webp" src="giphy.webp" />
  <img src="giphy.gif" alt="A GIF animation" />
</picture>

최적의 해상도 제공하기

이미지 전송에 있어 "모두에게 적합한" 방식의 접근법은 최상의 결과를 내지 못합니다. 작은 화면에서는 이미지를 낮은 해상도로, 큰 화면에서는 반대로 높은 해상도로 제공하고 싶을 것이기 때문이죠. 그 외에 높은 해상도를 갖는 화면 (예: "레티나") 기기에도 높은 해상도로 제공하고 싶을 것입니다. 그러므로 중간 해상도의 이미지 변형을 여럿 만드는 것 외에 적절한 파일을 알맞은 브라우저에 제공하는 방법이 필요합니다. 여기가 <picture>, <source> 요소를 mediasizes 속성을 활용해 업그레이드할 필요가 있는 지점입니다. 이 모든 속성들을 결합하는 방법에 대한 자세한 글은 여기에서 확인할 수 있습니다.

높은 해상도를 갖는 화면들을 다룰 땐 다음의 두 가지 흥미로운 효과들을 염두에 두세요.

다운로드되는 이미지의 우선순위 (그리고 순서) 제어하기

가장 중요한 이미지를 덜 중요한 것들보다 먼저 방문자들에게 보여주는 것은 사용자들이 인지하는 웹 성능을 높일 수 있습니다.

첫 번째 확인사항은 페이지 본문의 이미지들이 <img><picture> 요소를 사용하고 있는지, 그리고 배경 이미지들이 CSS의 background-image 속성으로 정의되고 있는지입니다. <img> 요소를 통해 참조된 이미지들은 배경 이미지보다 더 높은 로딩 우선순위가 부여됩니다.

둘째로, 우선순위 힌트(Priority Hints)가 도입되면서, 이미지 태그에 fetchPriority 속성을 적용하여 우선순위를 추가로 조절할 수 있습니다. 적절한 사용 예시로 이미지 캐러셀의 첫 번째 이미지가 이어지는 이미지들보다 높은 우선순위를 갖도록 구현하는 것이 있습니다.

렌더링 전략: 이미지 로딩 시 버벅거림 방지하기

이미지는 비동기적으로 로드되며, First Paint 이후에도 계속 로드되기 때문에, 만약 이미지의 크기가 로딩 전에 정의되지 않았다면 페이지 내용의 Reflow를 유발할 수 있습니다. 이미지가 로딩되면서 텍스트가 페이지 아래로 밀려 내려가는 예시가 이에 해당할 것입니다. 그렇기 때문에, 브라우저가 이미지가 표시될 공간을 미리 준비하도록 widthheight 속성을 설정하는 것이 중요합니다.

HTML <img> 요소에 포함된 이미지의 widthheight 속성은 이미지 로딩 전 브라우저가 이미지의 가로 세로 비율을 미리 계산하는 데 쓰입니다. 이미지 다운로드 후 화면에 표시될 때 이미지가 표시될 공간을 준비하고 Layout Shift를 줄이거나 더 나아가 예방하는 데에도 활용되죠. Layout Shift를 줄이는 것은 좋은 사용자 경험과 웹 성능의 주요한 부분입니다.

브라우저는 이미지를 포함한 모든 자산이 다운로드되기 전, HTML이 구문 분석될 때 콘텐츠 렌더링을 시작합니다. 이미지 크기를 포함시키면 브라우저가 최초의 페이지 렌더링 시 각 이미지가 표시될 정확한 크기의 플레이스홀더를 준비할 수 있습니다.

첫 번째는 이미지가 없지만 공간이 준비되어 있는 이미지, 두 번째는 이미지가 준비된 공간으로 로딩되는 이미지

widthheight 속성이 없다면 플레이스홀더 공간이 만들어지지 않기 때문에, 페이지 렌더링 후 이미지 로드 시점에 눈에 띄는 버벅거림(jank)나 Layout Shift가 생깁니다. 페이지 Reflow와 Repaint 모두 성능과 사용성 문제에 해당하죠.

반응형 디자인에서는 이미지를 담는 공간의 가로 길이가 이미지보다 작을 경우 이미지가 그 공간을 벗어나지 않도록 하기 위해 보통 다음의 CSS를 사용합니다.

css
img {
  max-width: 100%;
  height: auto;
}

이 방법은 반응형 레이아웃에는 유용하지만 너비 및 높이 정보가 포함되어 있지 않을 경우 버벅거림을 유발합니다. <img> 요소가 파싱되었지만 이미지는 로드되기 전에 높이 정보가 없을 경우엔 높이를 0으로 설정한 것과 같은 효과를 주기 때문이죠. 페이지가 화면에 최초로 렌더링된 후 이미지 로드 시점에 페이지는 Reflow, Repaint되며 새로 설정된 높이를 위한 공간을 만들면서 Layout Shift가 생깁니다.

브라우저는 실제로 이미지가 로드되기 전 이미지의 크기를 정하는 메커니즘을 갖고 있습니다. <img>, <video>, <input type="button"> 요소에 widthheight 속성이 설정되어 있으면 브라우저는 이를 통해 가로 세로 비율을 로드 시간 이전에 계산하고 활용할 수 있습니다.

가로 세로 비율은 그 다음으로 이미지의 높이를 계산하는 데 쓰이고, 그 결과 <img> 요소의 정확한 크기가 적용됩니다. 이렇게 되면 경우 이미지 로드 시 앞에서 얘기한 버벅거림이 아예 일어나지 않거나 최소화됩니다. 목록으로 주어진 이미지 크기들이 정확하지 않더라도 말이죠.

가로 세로 비율은 이미지 로드 시 공간을 준비하는 데에만 쓰입니다. 이미지가 로드된 후에는 속성들에서 계산된 값이 아닌 로드된 이미지 자체의 가로 세로 비율이 사용됩니다. 이는 크기 속성들이 정확하지 않은 경우에도 이미지가 정확한 가로 세로 비율로 표시될 수 있도록 해줍니다.

지난 10년 동안 HTML에 <img> 태그에 이미지를 쓸 때 widthheight 속성을 생략하는 것이 개발자 모범 사례로 추천되었었지만, 가로 세로 비율 매핑으로 인해 이제는 이 두 속성을 포함시키는 것이 모범 사례입니다.

배경 이미지의 경우, 이미지가 다운로드되기 전에도 그 위의 표시될 내용을 읽을 수 있도록 background-color 속성을 설정하는 것이 중요합니다.

결론

이 섹션에선 이미지 최적화에 대해 살펴보았습니다. 이제 평균 웹사이트 데이터 전송량의 절반에 달하는 부분을 최적화하는 방법에 대해 전체적으로 이해했을 것입니다. 이미지는 사용자들의 데이터 전송량을 소모하고 페이지 로딩을 느리게 하는 단 하나의 미디어 유형일 뿐입니다. 다음에는 데이터 전송량의 소모의 20%를 차지하는 비디오를 최적화하는 방법에 대해서 살펴보겠습니다.