main-logo

이미지 성능 최적화

next/image 컴포넌트 적극 활용하기

profile
sunny
2023년 06월 24일 · 0 분 소요

들어가며

운영 중인 서비스 NILE은 오픈한 이래로 NFT 출시와 DAO 출범 등 활발한 활동이 이어지고 있습니다. 사용자가 점차 늘어가면서 이에 따른 성능 개선 작업의 중요성 또한 커지게 되었습니다. NFT 상품 이미지의 경우 크기 규격이 화면에 노출되는 디자인 대비 크며, 이미지 하나당 용량이 1MB~4MB 입니다. 요청 이미지 수만 300개가 넘는 메인 페이지의 초기 로딩 시간이 상당히 소요되었습니다. 지난 1달 동안 이미지 성능 개선을 위해 수정한 내용을 소개합니다.


이미지 전략

이미지 유형에 따라 적절한 이미지 포맷을 이용하기

정적인 이미지이자 픽셀 베이스의 그래픽이나 이미지 포맷 형식 중 흔히 사용하는 것은 jpg, png입니다. 흔히 퍼블리싱 작업 시 투명한 배경 사용 여부에 따라서 jpg, png로 구분 지어 이미지 포맷 형식을 결정합니다.

  • jpg 포맷

    이미지를 손실 압축해서 파일 크기를 줄여서 웹사이트에서 로드 시간을 단축해서 사용할 수 있습니다.

  • png 포맷

    이미지를 무손실 압축하고 투명한 배경이 있는 그래픽을 처리할 수 있습니다.

구글이나 넷플릭스와 같은 대량의 이미지 데이터 통신량이 많은 곳에서 고효율 이미지에 대응하는 새로운 이미지 포맷에 대한 필요성이 높아지면서, 2010년 구글의 WebP(weppy, 웹 피)와 2019년 Alliance for Open Media가 avif 포맷을 개발하게 됩니다.

  • webp 포맷

    jpg 이미지를 대체하기 위해 제시된 규격이지만, jpg, png, gif 세 포맷 모두 압축 효율을 높여 웹사이트 전송량 감소와 로딩 시간을 단축합니다. 동일 화질의 이미지를 JPEG 대비 25~34%, PNG 대비 26% 적은 용량으로 압축시켜줍니다.

  • avif 포맷

    jpg, png, gif 상용 이미지 포맷을 대체하여 압축 효율이 높은 점은 webp와 같지만, 손실 압축 이미지 포맷인 경우는 jpg 대비 50%, webp 대비 20% 이미지 용량을 압축시켜 webp보다는 성능은 좋지만, 무손실 압축은 webp 나 png보다 효율이 낮아질 수 있습니다.

webp, avif 는 브라우저 지원 범위는 OS 버전별 조금씩 다른데, 아래 이미지를 참고해주세요.

  • webp 브라우저 지원 범위
webp.png
  • avif 브라우저 지원 범위
avif.png
// 예 next.config.js

module.exports = {
  images: {
    formats: ['image/avif', 'image/webp'],
  },
};

이미지 규격 정의하기

이미지의 용량은 크기로 비례하기 때문에 적절한 이미지의 크기를 사용하는 것이 중요합니다. 기존 사이트 서버에 저장된 NFT 이미지 크기는 1280 * 1280px 이지만, 브라우저에서 요청하는 이미지 크기는 240, 288, 420px 크기로 이미지 규격과 원본 이미지 자체 용량 경량화를 디자인팀에 요청하였습니다.

또한 next/image에서 제공하는 디바이스별 반응형 이미지를 제공하도록 설정해주었습니다. Image 컴포넌트에 layout=“fill” 값을 넣어주고 next.config.js 폴더 내 반응형 브레이크를 지정해주면 화면별 적절한 이미지를 제공해줍니다.

// 예 next.config.js
module.exports = {
  images: {
    deviceSizes: [360, 674, 1024, 1280, 1440],
  },
};

이미지 레이지 로딩하기

브라우저의 뷰포트 거리에 도달했을 때 리소스 요청하는 레이지 로딩을 이용하면 리소스를 한꺼번에 불러오는 방식보다는 초기에 적은 데이터를 요청하여 화면을 더 빠르게 렌더링할 수 있습니다. next/image에서 제공하는 loading="lazy" 속성을 이용하면 간편하게 적용할 수 있는데요,

  • loading=“eager”

    페이지 위치 상관없이 초기에 이미지 리소스를 네트워크에 요청합니다. 아래 영상에서 우측 개발자 네트워크 탭에서 “요청 265건”이 페이지 로드 시 이미지를 요청하는 모습을 확인할 수 있습니다.

  • loading=“lazy”

    페이지가 뷰포트에 도달했을 경우 이미지 리소스를 네트워크로 요청합니다. 아래 영상에서 초기 로드는 81건에서 스크롤이 될 때마다 요청 수가 늘어나는 것을 확인할 수 있습니다.

// 예) Image Component
<Image src="./cover.png" layout="fill" loading="lazy" alt="background-image styling" />

CSS

<img> 태그가 아닌 CSS background 속성으로 이미지를 처리하는 이유는 cover 속성을 사용의 목적이 가장 크지만, CSS로 이미지를 로딩하는 경우는 이미지 최적화가 되지 않아서 SEO 측면이나 사이트 성능에도 좋지 못합니다. 의미가 있는 이미지의 경우는 next/image 컴포넌트에 objectFit="cover" 속성을 이용해서 스타일링을 해주고 이미지의 alt 속성으로 부연 설명을 해주었습니다.

// 예) Image Component
<Image src="./objectfit.png" layout="fill" objectFit="cover" alt="object-fit styling" />
  • 개선 전

cover.png

  • 개선 후

objectfit.png



마치며

프로젝트 진행하면서 여유가 생길 때마다 조금씩 진행하다보니 전체적으로 코드 반영이 되지 못한 부분과 코드적인 개선 작업들이 많지만, 남은 기간 동안 열심히 수정해서 지금보다 더 쾌적하게 사이트를 이용할 수 있도록 노력해야겠습니다. 성능 관련되어 이리저리 조언과 가이드를 주셨던 류중열 팀장님께 감사드립니다.

부족한 부분, 잘못된 내용이 있다면 댓글로 알려 주시면 수정하겠습니다.

읽어주셔서 감사합니다.

참고문서