SSR 페이지에서 이미지 최적화와 CLS 개선을 위한 Next.js Image 컴포넌트 활용법

1. 배경

Next.js에서 SSR(Server-Side Rendering)로 페이지를 렌더링할 때, 이미지 최적화는 사용자 경험을 개선하는 중요한 요소입니다. 이전에는 커뮤니티 리스트 페이지(SSR)에서 이미지를 서버에서 크기를 조정하여 제공하는 Picture 컴포넌트를 사용했지만, 이 방식은 몇 가지 문제가 있었습니다.

레이지 로딩 미지원: 이미지가 페이지에 로드될 때, 레이지 로딩이 없기 때문에 모든 이미지를 한꺼번에 로드하게 되었습니다. 플레이스홀더 미지원: 이미지가 로드될 때까지 공백이 생겨 사용자 경험에 부정적인 영향을 미쳤고, CLS(Cumulative Layout Shift) 문제가 발생했습니다. 파일 크기 문제: 최적화된 이미지를 제공하지 않아 페이지의 데이터 크기가 커졌습니다. 이에 따라 Next.js의 Image 컴포넌트를 활용하여 이러한 문제를 해결하기로 했습니다.

이와 같은 문제를 해결하기 위해 Next.js의 Image 컴포넌트를 도입하여 최적화를 진행했습니다. Image 컴포넌트는 기본적으로 레이지 로딩과 플레이스홀더 기능을 지원하고, 다양한 포맷 및 최적화 옵션을 제공해 더욱 손쉽게 성능을 개선할 수 있습니다.


2. 기존 이미지 최적화 방식의 문제점

기존에 사용하던 Picture 컴포넌트는 다음과 같은 방식으로 이미지를 렌더링했습니다.

interface IPicture { thumb: string; name?: string; className?: string; w?: number | undefined; } const Picture = ({ thumb = '', name, className, w = 1200 }: IPicture) => { return ( <picture className={className}> {thumb && ( <> <source type="image/webp" data-srcset={`${thumb}?w=${w}&f=webp`} srcSet={`${thumb}?w=${w}&f=webp`} /> <source data-srcset={`${thumb}?w=${w}`} srcSet={`${thumb}?w=${w}`} /> <img src={thumb} alt={name || ''} /> </> )} </picture> ); };

위의 코드는 서버 기반 리사이징과 WebP 포맷을 활용한 이미지 최적화 로직을 포함한 Picture 컴포넌트입니다. 이 컴포넌트는 thumb URL을 받아 이미지의 크기를 조정하고, WebP 포맷을 우선 제공하도록 구성되어 있습니다.

1) 서버 기반 이미지 리사이징의 장점

서버에서 이미지 크기를 리사이즈하면 클라이언트에 적절한 사이즈의 이미지만 전송할 수 있어, 불필요하게 큰 이미지 파일을 로딩할 필요가 없어집니다. 이렇게 하면 모바일 기기와 같은 낮은 대역폭 환경에서도 페이지 로딩 속도가 개선됩니다.

2) WebP 포맷 활용

WebP는 Google에서 개발한 이미지 포맷으로, JPEG나 PNG보다 파일 크기를 줄이면서도 화질을 유지할 수 있는 포맷입니다. 대부분의 최신 브라우저에서 지원되기 때문에 이미지 최적화에 효과적입니다.

3) 서버와의 협력으로 최적화 구현

이 컴포넌트는 이미지 URL에 파라미터로 w 값을 추가해 서버가 해당 크기로 이미지를 리사이즈할 수 있도록 합니다. 예를 들어, thumb이 https://example.com/image.jpg라면, https://example.com/image.jpg?w=1200과 같은 URL을 통해 서버가 리사이징된 이미지를 반환하도록 설정합니다. 이 방식으로 클라이언트에서는 불필요하게 큰 이미지를 다운로드하지 않고, 필요한 크기의 이미지만을 가져올 수 있습니다.

4) 최적화의 효과

이렇게 서버 리사이징과 WebP 포맷을 활용하면 페이지 로딩 속도가 눈에 띄게 개선됩니다. 특히, 대용량 이미지가 많은 페이지에서 성능 향상을 경험할 수 있으며, 사용자는 빠르고 최적화된 경험을 누릴 수 있습니다.

5) 문제점

이 방식은 서버에서 크기 조정과 WebP 포맷을 지원하는 장점이 있었지만, 레이지 로딩과 플레이스홀더를 지원하지 않아 렌더링 성능과 사용자 경험이 저하되는 문제가 있었습니다. 특히, 이미지를 뒤늦게 로딩하면서 CLS가 발생하여 페이지 레이아웃이 흔들리는 문제가 있었습니다.


3. Next.js Image 컴포넌트로 전환

이 문제를 해결하기 위해 Next.js의 Image 컴포넌트를 도입했습니다. Image 컴포넌트는 기본적으로 레이지 로딩과 플레이스홀더 기능을 지원하여 CLS 문제를 방지하고 성능을 최적화할 수 있습니다.

import Image from 'next/image'; <p className="pic" key={image.id}> <Image alt={image.file} src={`${image.file}?w=${600}&f=webp`} placeholder="blur" blurDataURL="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mN8Vw8AAmEBb87E6jIAAAAASUVORK5CYII=" width={600} height={600} quality={85} style={{ maxWidth: '100%', height: 'auto', }} /> </p>

코드 설명

  • src: 서버에서 리사이징된 이미지 URL을 사용하여 최적화된 이미지를 제공합니다.
  • placeholder="blur": 이미지를 불러오는 동안 블러 효과를 적용하여 사용자가 로딩 중임을 인식할 수 있도록 합니다.
  • blurDataURL: 로딩 중일 때 표시할 저화질 이미지의 Base64 URL을 지정하여 플레이스홀더로 사용합니다.
  • quality: 이미지 품질을 설정하여 불필요하게 큰 파일 크기를 줄이고 최적화된 품질을 제공합니다.
  • width와 height: 고정된 크기를 지정하여 CLS 문제를 방지합니다.

4. Next.js Image 컴포넌트를 활용한 최적화 효과

Next.js Image 컴포넌트로 전환하면서 다음과 같은 개선이 이루어졌습니다.

  • CLS 문제 해결: 고정된 이미지 크기와 플레이스홀더로 레이아웃 이동 문제를 방지하여 사용자 경험을 향상했습니다.
  • 레이지 로딩 지원: Image 컴포넌트는 기본적으로 레이지 로딩을 지원하여 화면에 보이는 이미지부터 로드하여 불필요한 리소스 소비를 줄입니다.
  • 플레이스홀더로 사용자 경험 개선: 블러 처리된 플레이스홀더 이미지를 통해 로딩 중에도 부드러운 사용자 경험을 제공합니다.
  • 데이터 크기 감소: 필요에 맞게 최적화된 품질과 사이즈의 이미지만 로딩되므로 페이지 로딩 속도가 개선되었습니다.

5. 결론

Next.js Image 컴포넌트를 사용하여 이미지 최적화와 사용자 경험을 동시에 개선할 수 있었습니다. 특히 SSR 방식으로 렌더링되는 페이지에서 초기 로딩 시간을 단축하고, CLS 문제를 해결하여 사용자 피드백을 반영한 최적화를 이루어냈습니다. 이미지 최적화는 성능 최적화의 핵심 요소 중 하나이므로, 프로젝트에서 비슷한 문제를 겪고 있다면 Image 컴포넌트 도입을 고려해보세요.


참고 Transparent Base64 PNG Pixel generator https://github.com/vercel/next.js/tree/canary/examples/image-component

JP
이중표Frontend Engineer

3년차 프론트엔드 개발자. Next.js, React, TypeScript 기반 웹 애플리케이션 개발 전문. 대규모 트래픽 환경에서 SSR·ISR 렌더링 전략 설계 경험.

이력서 보기