본문 바로가기
Web/Next.js

Next.js의 이미지 최적화와 <Image /> 컴포넌트

by 가나닩 2024. 12. 13.

웹사이트의 이미지 최적화는 속도 최적화와 검색엔진 최적화 크게 두단계로 나눠볼 수 있다.

 

1. 기본 이미지 최적화 방법

웹사이트를 제작할때는 수많은 이미지가 사용된다. 대부분의 웹사이트는 이미지가 차지하는 용량이 아주 크고, 최적화가 이루어지지 않은경우 더욱더 커지게 된다.

이미지 사이즈 최적화는 웹페이지 최적화의 기본이다.

1-1. 이미지 포맷 선택

흔히 알고있는 이미지 포맷은 JPEG(JPG), PNG, GIF이다. 

  • JPEG(JPG) : 주로 사진, 복잡한 이미지에 사용한다. 손실압축 방식을 사용하여 사진의 품질이 조금 떨어지는대신 용량을 크게 줄일 수 있다. 투명도를 지원하지 않는다.
  • PNG : 주로 그래픽, 로고, 패턴 등의 이미지에 사용한다. 비손실 압축방식을 사용하여 일반적으로 JPEG보다 용량이 크지만 품질이 보장된다. 투명도를 지원한다.
    그러나 사용되는 그래픽, 로고, 패턴 등의 경우에는 JPEG과 후술할 webp, avif보다 용량이 작은 경우도 있다.
  • GIF : 애니메이션 이미지 제작에 주로 사용되며 비손실 압축방식을 사용한다. 하지만 256색밖에 지원하지 않아 이미지 품질이 떨어질 수 있다.

이외에 최근 많은곳에서 사용되는 새로운 이미지 포맷이 있다.

  • WebP : 구글에서 개발한 이미지 포맷으로 손실,비손실 압축이 모두 가능하며 애니메이션 기능도 지원해 JPEG, PNG, GIF를 모두 대체할 수 있다. 일반적으로는 차세대 포맷인만큼 기존 이미지 포맷보다 더 작은용량으로 이미지를 최적화할 수 있지만 IE를 지원하지 않고 프로그레시브 이미지 기능(이미지가 상단에서 순차적으로 로딩되는것)을 지원하지 않는다.
  • AVIF : 최근 사용되는 이미지 포맷중에서는 가장 늦게 개발된 포맷으로 AOMedia에서 개발했으며 WebP와 동일하게 손실, 비손실 압축과 애니메이션 모두를 지원해 기존 이미지포맷을 모두 대체할 수 있다. 일반적으로는 WebP보다도 더욱 좋은 압축효율을 보여주지만 범용성이 낮은편이라 호환되지않는 환경이 비교적 많은 편이다. 브라우저 호환성에 문제가 없다면 Next.js는 AVIF를 사용할 수 있다.

이미지 포맷은 이외에도 매우 다양하지만 브라우저 호환성과 사용하는 이미지의 종류와 용도, 최적화의 방향성에 따라서 가장 적합한 포맷을 선택해야한다.

 

1-2. 이미지 사이즈 조절

높은 화소의 스마트폰이나 카메라로 촬영한 사진은 이미지의 가로세로 크기가 매우 큰편이다.

일반적인 스마트폰 전면카메라의 화소인 1200만화소 카메라는 보통 가로사이즈가 4000픽셀 이상이며 2억화소까지 올라간 스마트폰 카메라로 촬영한 사진은 가로사이즈가 10000픽셀을 넘어가기도 한다.

 

하지만 일반적인 웹사이트 제작에는 그정도로 큰 사이즈의 이미지가 필요하지 않다. 웹페이지 디자인과 용도에 따라 이미지 크기를 조절해서 사용해야한다.

 

1-3. Image CDN

CDN은 Content Delivery Network의 약자로 웹사이트의 정적 콘텐츠를 효과적으로 전송하기 위해 사용된다. CDN 서비스 제공자는 전 세계에 분산된 서버를 이용하여 이미지를 요청하는곳에 보다 빠르게 제공한다. 쉽게말하면 가까운곳에서 데이터를 가져오도록 해주므로 더욱 빠르게 로드할 수 있다는 특징을 가지고있다. 또한 URL Parameter를 통해 이미지를 불러올때 여러가지 옵션을 이용할수도 있다.

 

 

1-4. 여러 버전의 이미지 제공

사용자의 브라우저환경(viewport 등)에 따라 다른 이미지를 제공하여 최적화를 할수도 있다.

<img /> 태그에서 사용할 수 있으며 이는 Next.js의 <Image /> 내장 컴포넌트에도 비슷하게 적용할 수 있다.

<img
  src="large.jpg"
  srcset="
    small.jpg 300w,
    medium.jpg 600w,
    large.jpg 900w
  "
  sizes="(max-width: 600px) 300px, (max-width: 900px) 600px, 900px"
/>

 

1-5. CSS sprite

보통 이미지를 불러올때는 필요한 곳에 필요한 이미지를 하나하나 불러와서 집어넣게 되는데 페이지 내에 수많은 이미지가 존재할경우 그 수 만큼 불러오기를 실행해야한다.
페이지에 필요한 모든 이미지를 한 이미지에 한번에 그려놓은 뒤 필요한 부분을 잘라서 사용하는 방식이다. 하나의 이미지만 불러오면 되기때문에 최적화에 유리하다.

 

※ 참고 - 합쳐진 이미지가 어떤 형식인지 확인할 수 있다.

CSS Image Sprites

 

W3Schools.com

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

 

 

 

1-6. 이미지 고정값을 이용해 reflow 방지

reflow는 브라우저가 DOM트리를 다시 계산하면서 화면을 재배치 할때 발생한다. 화면이 재배치되면 UI가 흔들리거나 깜빡이는 문제가 생길 수 있다. 만약 여러개의 이미지에서 이런 현상이 발생한다면 유저에게 매우 불편하게 느껴질 수 있다.

 

이 현상이 생기는 이유는 브라우저가 이미지를 로드하고 렌더링하기까지 이미지의 크기를 알수없기 때문이다.

이를 방지하기 위해서 이미지의 크기 혹은 비율을 미리 알려주고 브라우저가 여기에 맞는 공간을 미리 만들어두도록 하여 UI의 흔들림이나 깜빡임을 해결할 수 있다.

 

HTML의 img 요소에서 이미지의 크기를 미리 지정할 수 있다.

<img src="image.jpg" width="300" height="200" alt="Example Image" />

 

css에서 이미지의 비율을 지정할수 도 있다.

.image {
    width: 100%;
    aspect-ratio: 3 / 2; /* 이미지의 비율을 미리 지정 */
}

 

 

1-7. Lazy Loading

한 페이지에 매우 많은 이미지가 있을경우 이를 한번에 로드하려고 하면 초기 페이지 로딩시간이 매우 길어질 수 있다.

사용자가 현재 보고있는 이미지만 먼저 로드하고 유저 입력에 따라 화면이 바뀌면 (스크롤, 팝업창 등) 해당 부분의 이미지를 필요할때 로드하도록 하는 방식이다.

 

가장 간단한 방법으로는 HTML의 img 요소에 loading="lazy"를 추가하면 된다.

<img src="image.jpg" loading="lazy" alt="Example Image" />

 

HTML5에서 추가된 기능으로 이미지가 viewport 내에 들어오면 로딩하도록 한다. 복잡한 과정 없이 lazy loading을 구현할 수 있다. 이것보다 사용자의 스크롤, 현재 viewport 상태 등을 모니터링하여 원하는대로 이미지 로딩을 지연시키기 위해서는 자바스크립트를 적극적으로 활용해야한다.

viewport 내에 특정 요소가 들어왔는지 확인하는 방법으로는 IntersectionObserver가 자주 사용된다.

 

2024.04.14 - [Web/React] - 무한스크롤 : IntersectionObserver와 useRef

 

무한스크롤 : IntersectionObserver와 useRef

검색결과 등과 같이 방대한 양의 데이터를 화면에 표시하고 싶은 경우가 있다. API요청등을 통해 수많은 결과를 한번에 가져오고 화면에 표시하면 프로그래밍 난이도는 낮아지겠지만 여러가지

cstelladev.tistory.com

 

 

2. Next.js의 Image 컴포넌트

Next.js에서는 여러가지 이미지 최적화를 손쉽게 구현할 수 있는 Image 컴포넌트를 제공해준다. 주요 특징은 다음과 같다.

  1. 형식 최적화 : webp등 브라우저에 적합한 형식으로 변환한다. (브라우저에 맞춰서 변환한다.)
  2. 사이즈 최적화 : srcset 속성을 자동으로 생성해서 다양한 viewport 크기에 맞는 이미지를 제공한다.
  3. 지연 로딩 : lazy loading이 기본으로 적용되어있다. (priority로 비활성화 가능)
  4. placeholder : 이미지 로드 전 특정 이미지를 blur 효과를 적용하여 미리 보여줄 수 있다.
  5. 반응형 이미지 조정 : layout 옵션을 제공해서 페이지에서 이미지가 어떻게 로드될지 지정할 수 있다.

 

Image 컴포넌트를 사용하면 앞서 설명했던 이미지 최적화 방법들 대부분을 손쉽게 적용할 수 있다. 또한 src, alt, layout 옵션 등 최적화와 접근성 향상, SEO에 중요한 요소들이 빠졌을때도 경고를 해줘 도움이 된다.

 

2-1. 이미지 import해서 사용하기

일반적으로 Image 컴포넌트를 사용할때는 reflow로 인한 layout shift를 방지하기 위해 width, height같은 사이즈 속성이나 layout 같은 속성을 필수로 넣게된다. 로컬 이미지를 경로를 통해 사용하거나 온라인의 이미지를 URL로 사용하는 경우이다.

<Image src="/logo.png" width={100} height={100} alt="Logo" />
<Image 
  src="https://example.com/image.jpg" 
  width={800} 
  height={400} 
  alt="External Image" 
/>

 

 

그러나 로컬의 이미지를 import 하여 사용할때는 속성들을 필수로 명시하지 않아도 된다.

import exampleImage from '/public/example.jpg';

<Image src={exampleImage} alt="Example Image" />

 

import한 이미지는 Next.js가 해당 이미지를 정적 파일로 처리하면서 크기를 자동으로 계산하기 때문이다.

 

이외에 Image 컴포넌트의 정보와 사용할 수 있는 다양한 속성은 아래 링크에서 확인할 수 있다.

Optimizing: Images | Next.js

 

Optimizing: Images | Next.js

Optimize your images with the built-in `next/image` component.

nextjs.org

Components: <Image> | Next.js

 

Components: <Image> | Next.js

Optimize Images in your Next.js Application using the built-in `next/image` Component.

nextjs.org

 

 

 

3. 결론

웹페이지를 개발할때 이미지 최적화는 매우 중요하다. 단순 텍스트, JS파일 보다 훨씬 큰 용량을 차지하기 때문에 매우 큰 이미지에 최적화를 해주지 않으면 로딩시간이 길어질 수 있고 인터넷 속도가 느린 환경에서는 그 차이가 더욱 커지게 된다. 페이지 로딩이라는 측면 외에도 검색엔진 최적화와 접근성 향상, 유저 경험 향상을 위해 꼭 진행해야 한다.

 

하지만 최적화해야할 부분이 많은만큼 익혀야 할 내용도 매우 많다. 잘못된 방식을 사용할경우 오히려 최적화에 방해가 될 수도 있다. 특히 Next.js의 Image 컴포넌트의 경우 사용할 수 있는 속성의 종류가 매우 많고 기본적으로 동작하는 기능이 많은 컴포넌트이기때문에 정확한 사용법을 익힐 필요가 있다.