구글소셜로그인으로 가져온 이미지 next/image로 최적화하기

j_wisdom_h·2024년 2월 26일
0

Next.js 프로젝트

목록 보기
7/8
post-thumbnail

❗ 발단

구글소셜로그인으로 가져온 이미지를 헤더에 표시하고 싶어 Image태그를 썼다.

❗ 문제

그런데 화질이 너무 깨진다.

다른 포스팅과 달리 이 포스팅은 화질을 개선하는 과정에서 최적화를 다룬다.

next/image 소개

로컬에서 이미지를 가져올 경우 (public 폴더에서 상대경로)

import Image from 'next/image'
 
export default function Page() {
  return (
    <Image
      src="/profile.png"
      width={500}
      height={500}
      alt="Picture of the author"
    />
  )
}

remote로 이미지를 가져올 경우, (구글 소셜로그인 포함)

const nextConfig = {
	...
	images: {
	        remotePatterns: [
	            {
	                protocol: 'https',
	                hostname: 'lh3.googleusercontent.com',
	                port: '',
	                pathname: '/a/**',
	            },
	        ],
	    },
}

리모트 이미지의 경우 Next.js 서버에서 이미지를 가지고 있는 리모트 서버에 직접 요청을 하기 때문에 모든 url에 대한 접근을 허용할 경우 악의를 가진 사용자에 의해 공격을 받을 가능성이 있다.

이를 방지하기 위해 이미지를 서빙하는 서버가 안전한 서버라는 것을 Next.js에 알려줘야 한다. next.config.js 파일에 CDN의 host를 명시하자.

Image props

❗ html img, next.js의 Image 비교 (width: 45px 기준으로)

html img 태그 사용 시,

next.js의 Image 태그

💡 next.js의 Image 태그 사용시 file size가 확연히 줄어듬(7.1kb > 750B)
=> 98.94% 줄어듬
💡 파일크기가 줄어든 것이 화질이 깨지는 문제와 연관이 깊다.

  • intrinsic size는 고유사이즈로, Image 태그 사용시 고유사이즈 자체를 줄여 최적화하는 방식으로 작동하는 것으로 추정됨( html image 96x96, next.js Image 48x48)

next.js의 Image 태그 quality 100

  • props quality(defautl 75, 1~100)로 화질을 개선할 수 있지만 , 원하는 만큼 화질이 개선되지 않았음.

next.js의 Image 태그 quality 100 + fill props 이용

fill

width와 height를 모를 때 사용하기 유용하다. width, height를 입력하지 않아도 된다.
부모요소가 position: "relative"position: "fixed", or position: "absolute" 일 경우 사용할 수 있다.
부모의 요소 크기에 맞게 채워진다.

fill을 사용하게 되면 고유사이즈가 96x96으로 기존 48x48보다 커졌다. 물론 파일 크기도 커졌다. 그리고 육안으로 볼 때도 화질이 개선되었다.

<Image
    src={userImageURL}
    fill={true}
    quality={100}
    style={imageStyle}
    alt="avatar"
  />

❗그렇지만 current source를 자세히 보면 w=1920이 있다.

엥 width크기가 오히려 더 커진걸까? 원하는 사이즈보다 훨씬 큰 걸?
더불어 화면에 이미지가 가득 찼다가 지정해준 크기로 돌아가는 현상도 발생했다.

💡 sizes 속성

sizes는 미디어 쿼리와 비슷한 형태의 속성으로, 이미지가 다른 화면 크기(브레이크포인트)에서 얼마나 넓게 표시될지에 대한 정보를 제공한다.

fill 속성을 사용하거나 반응형 크기로 스타일이 지정된 이미지의 경우, sizes 값은 성능에 큰 영향을 미친다.

왜냐하면 fill 속성과 함께 사용하는 이미지에 sizes 값을 지정하지 않으면 기본값인 100vw (전체 화면 너비)가 사용되기 때문이다.

⭐ 따라서 Next/Image에 sizes에 대한 어떤 정보도 설정하지 않았기 때문에 결국 화면을 꽉 차는 사이즈인 3840px의 이미지가 로드되었던 것이다.

💡 해결법

sizes를 명시해주자.

[ 기존 Image 태그 ] + fill속성

<Image
 	src={userImageURL}
	fill={true}
	quality={100}
	style={imageStyle}
	alt="avatar"
/>



네트워크탭에서 w=1920, 230B, 39ms

[ 기존 Image 태그 ] + fill속성 + sizes속성 추가

<Image
 	src={userImageURL}
	fill={true}
	quality={100}
	style={imageStyle}
	alt="avatar"
    sizes="45px"
/>


네트워크탭에서 w=48, 230B, 44ms

흠 오히려 네트워크 시간은 늘었지만, width는 줄어들었다. 파일크기도 줄어들었다.

또한 화면에 이미지가 가득 찼다가 지정해준 크기로 돌아가는 현상도 없어졌다!

그런데 sizes =45px 로 했는데 왜 w=48로 이미지를 로드하는 것일까?

srcset은 해당 사이즈보다 크지만 그 중에서 가장 작은 사이즈를 찾아 그만큼의 사이즈를 로드한다.

// images.imageSizes, images.deviceSizes 미지정 시 설정되는 default 값
module.module.exports = {
  images: {
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
  },
};
  • deviceSizes : 디바이스 breakpoint 기준점
    이미지 너비 목록으로 deviceSizes와 연결되어 전체 srcSet을 형성한다.

  • imageSizes는 sizes props이 사용될 때 deviceSizes 보다 작음을 나타낼 때의 이미지에만 사용된다고 한다.

따라서 sizes='45px'보다 큰 것 중 가장 작은 48이 선택된 것이다.

그치만 또 화질이 깨진다. 그래서 sizes를 좀 더 크게 지정해 개선했다.
( fill = {true}, quality={100} 조건 하에)

  • sizes 적용전 (w = 1920)
  • sizes = 45px (w = 45)적용후
  • sizes = 64px (w = 64)적용후

확대한 것이라 화질이 많이 안 좋아보이지만! 전체로 볼 때는 적당한 화질을 갖는다.

적당한 크기로 화질개선하기 성공!!

<Image
                    src={userImageURL}
                    style={imageStyle}
                    alt="avatar"
                    width={45}
                    height={45}               
 />


파일크기 : 750B

                <Image
                    src={userImageURL}
                    fill={true}
                    quality={100}
                    style={imageStyle}
                    alt="avatar"
                    sizes="64px"
                />


파일크기 : 2.8kb

기타 next/image props

Next.js는 이미지를 webp와 같은 용량이 작은 포맷으로 이미지를 변환해서 제공한다.

💡loading = "lazy"
스크린에 element가 보일 때를 캐치하여 이미지를 로드하도록 자동 구현 되어있음

💡srcset

기기의 디스플레이 너비에 따라 다른 이미지를 사용자에게 제공하려는 경우 srcset 속성을 사용한다.

srcset는 화면이 작은 기기에서 데스크탑 디스플레이처럼 큰 이미지가 필요하지 않기 때문에 작은 이미지 파일을 제공하는 문제를 해결한다 — 또한 선택적으로 고해상도/저해상도 화면에 다른 해상도 이미지를 제공할 수도 있다.

profile
뚜잇뚜잇 FE개발자

0개의 댓글