프로젝트

웹 성능 최적화 - 1. 이미지

3jun 2022. 10. 26. 14:46

최근 개인적으로 진행하고 있는 사이드 프로젝트의 화면이다.

gif 파일을 검색하고 공유할 수 있는 플랫폼인 giphy.com을 클론하고 있다. 스크린샷에서 알 수 있다시피 대부분의 data가 img, video 파일들이다. 현재 진행상황은 랜더링과 검색기능만 간단하게 구현된 상태이며, 추가 기능 구현에 앞서 더 나은 ui를 위해 성능최적화 작업을 진행 중에 있다. 

라이트 하우스로 웹 성능을 측정해본 결과 형편없는 점수가 나왔다. 이미지 파일의 크기를 줄이기 위해 기존에 사용하던 img 태그 대신 next/image 를 사용하여 리팩토링을 진행했고, gif 파일형식 대신 webp 파일형식을 사용했으나 큰 차이는 없었다. 

 

원인 분석

이미지 성능을 개선하기에 앞서 웹 성능에 주요한 영향을 미치는 요인들에 대해서 분석을 해보고자 한다. 여기서의 핵심은 OPPORTUNITIES, DIAGNOSTICS 이다.

라이트 하우스 성능을 측정한 후 스크롤을 내리면 OPPORTUNITIES, DIAGNOSTICS 2가지 항목을 확인할 수 있는데,

OPPORTUNITIES 는 로딩 성능과 관련된 항목을, DIAGNOSTICS 는 랜더링 성능과 관련된 항목들을 보여준다.

2가지 항목에서 이미지 성능과 관련된 항목은 총 3가지 이다.

1. use video formats for animated content
2. properly size images
3. image elements do not have explicit width and height

우선 첫번째 use video formats for animated content 는 gif 이미지를 webp 형태로 가져오는데 이를 next/image 태그를 사용하여 랜더링 하기 때문에 발생한 문제로 보인다.

두번째와 세번째는 image가 들어갈 요소를 컴포넌트화 하여 동적으로 랜더링 하기 위해 width와 height 값을 고정된 값으로 주지 않고 뷰 로직을 구현해서 발생한 문제인 것으로 예상된다.  이 문제는 METRICS 항목에서 LCP (Largest Contentful Paint) 에도 부정적인 영향을 미치는 것으로 보인다. 

이미지 성능 개선방법

1.  차세대 이미지 형식 결정하기

이미지 형식에는 크게 4가지로 나눌 수 있다.

  •  png : 무손실 압축을 사용, 높은 품질의 이미지를 제공하지만 그만큼 큰 용량을 가지고 있다.
  • jpeg : 손실 압축을 사용하여, png에 비해 용량이 작다.
  • webp : 구글에서 2010년 발표한 것으로 jpeg 보다 더 나은 압축과 기능을 제공한다.
  • avif : AOMedia dptj 2019년 발표한 것으로 webp와 유사하게 높은 압축률을 자랑한다.

webp는 지원하지 않는 브라우저가 존재하므로 jpeg 파일과 함께 혼용해서 사용하는게 일반적이다.

<picture>
  <source type="image/webp" srcset="flower.webp">
  <source type="image/jpeg" srcset="flower.jpg">
  <img src="flower.jpg" alt="">
</picture>

이렇게 코드를 작성하면 webp를 지원하는 브라우저에서는 webp 형식을, 지원하지 않는 브라우저에서는 jpeg 형식을 사용할 것이다. 

2. 적절한 크기의 이미지 사용하기

랜더링된 이미지의 상세 정보를 확인해보면 다운로드된 이미지 원본의 크기는 랜더링될 이미지 크기에 비해 훨씬 큰 것을 확인할 수 있다.

따라서 랜더링 사이즈에 맞춰 이미지 크기를 조절한다면 이미지 최적화를 할 수 있다. 

랜더링 사이즈에 맞춰 이미지 크기를 조절하기 위해서는 반응형 이미지를 제공해야 한다.

 - srcser : 브라우저에 제시할 이미지 목록과 그 크기를 정의한다.
 - sizes : 화면 크기에 따른 어떤 이미지 크기가 최적인지 정의한다. 
 - 위 2가지 속성을 사용하는 방법을 제외하고 Image CDN을 사용하는 방법도 있다. 

3. CLS(누적 레이아웃 변경) 개선하기

CLS(누적 레이아웃 변경) 이란?
사용자가 예상치 못한 레이아웃 이동을 경험하는 빈도를 나타내는 수치로 시각적인 안정성을 의미한다.

이미지 요소에 명시적인 너비와 높이를 설정하지 않으면 쉽게 반응형으로 레이아웃을 구성할 수 있지만, 레이아웃의 잦은 변화를 유발하여 성능에 부정적인 영향을 준다.

width, height 값을 명시적으로 주는 방법도 있지만, aspect-ratio 속성을 사용하는 방법도 있다.

img {
  width: 100px;
  height: 200px;
}

img {
  width: 100px;
  height: 1/2;
}

4. 이미지 Lazy Loading

사용자에게 보여지는 이미지 외에도 현재 보이지 않는 이미지를 loading 하는 경우 네트워크 대역폭을 불필요하게 사용하는 경우가 있다.

이 때 사용할 수 있는 방법이 lazy loading 이다. 현재 보이는 이미지를 우선 load 하고 추후 다른 이미지들이 보이게 될 때 loading이 진행될 수 있도록할 수 있다.

<img width='100px' height='200px' loading='lazy' />

하지만 loading 속성을 지원하지 않는 브라우저도 존재하기 때문에 확인이 필요하다.

이 경우에는 intersection observer API 를 활용하여 이미지 요소가 화면에 들어왔을때 이미지를 load 할 수 있도록 코드를 작성할 수 있다.

5. 이미지 Pre Loading

이미지가 보이기 전에 미리 load 될 수 있도록 캐싱을 할 수 있다.

 

참고

[10분 테코톡] 록바의 웹 성능 개선하기 - 이미지
Medium, Responsive images with srcset and sizes, Wouter van der Zee