Next.js 공식문서를 보면서 커머스 사이트(와이즐리) 구현하기 (4)

undefined·2022년 12월 1일
0

<소스 참고>
https://github.com/kimtaru/commerce_by_next13

Image Optimization

넥스트에서는 기존 HTML의 img태그를 개량한 next/image를 제공합니다.

아래와 같은 점들이 개선되었다고 하네요.

  • 퍼포먼스 개선(장치별로 올바른 사이즈의 이미지를 제공)
  • Cumulative Layout Shift 방지(뒤늦게 로딩되면서 기존 레이아웃을 예상치 못하게 변경시키는 것을 방지함)
  • 뷰포트안의 이미지만 로드하여 페이지 로딩이 빠름

그럼 next/image 소스상에서 어떻게 적용해야 할까요?

next/image

browser issue

next/image는 이미지 로딩 방식은 lazy loading 방식입니다.

다만 브라우저의 버전을 확인하고 아래의 이슈를 핸들링 해야 합니다

  • Safari 15.4 이전에선 레이지 로딩이 적용되지 않을 수 있습니다.
  • Safari 12 이전에선 blur-up placeholder가 적용되지 않을 수 있습니다.
  • Safari 15 이전에선 width/height를 auto로 했을 시 Layout Shift 현상이 생길수도 있습니다.

사파리 15+ 부터 회색 경계선이 보이는 현상이 있고
파이어폭스 67+ 는 하얀색 배경이 보인다고 하네요.

그에 대한 대응이 나와 있으니 추후 동일현상 발생 시 적용해보도록 하겠습니다.


그런데 Lazy loding이 무엇일까요?

Lazy loading : 스크린안에 있는 이미지들만 먼저 로딩시키고 스크린 영역 밖에 있는 이미지의 로딩을 필요 시점 전까지 지연시키는 것을 의미합니다.
(이로서 메모리 사용 낭비를 줄이고, 페이지 로딩속도가 개선됩니다.)

이렇게 장점이 많은 next/image를 통해 화면에 이미지를 띄워보겠습니다.

next의 Image를 사용하기 위해 컴포넌트가 요구하는 Props에 대해 먼저 알아야 합니다.

Required Props

1.src

static image file을 사용하고자 한다면 해당 컴포넌트에서 import하여 사용하면 됩니다.
외부에 이미지 관리 서버가 있고 가져와야 한다면 path string을 세팅해야 합니다.

loader 속성을 사용하면 축약된 표현의 src세팅이 가능합니다.

만약 외부 URL을 명시해야 한다면 next.config.js에 해당 서버 도메인을 등록해주어야 합니다.

2.width

외부서버의 이미지라면 빌드시에 해당 이미지의 사이즈를 알 수가 없기 때문에 Image 컴포넌트에 파일 사이즈를 미리 명시해줘야 합니다.
하지만 외부 서버의 이미지 사이즈를 정확히 모른다면 어떻게 해야할까요?
그럴땐 Optional Props중 하나인 fill을 사용하면 됩니다.

3.height

width와 같습니다.

4.alt

스크린리더(시각장애인용)와 검색엔진에 해당 이미지 정보를 제공하는 alt속성은 반드시 정의해주어야 합니다.

Optional Props

Image Component에는 많은 Optional Props가 있습니다.

loader

로더는 인자를 받아 이미지를 얻을 수 있는 외부 서버 URL을 반환해주는 함수입니다.

next.config.js 설정을 통해 모든 next/image에 공통 로더함수를 적용하는 것도 가능합니다.

fill

이미지의 width와 height값을 모를 때 부모 div의 사이즈에 맞춰 이미지를 채워 넣을 것인지 여부를 결정하는 속성

부모 div는 position을 relative, fixed, absolute 중 하나는 반드시 가져야 한다.
object-fit이라는 CSS 속성과 함께 쓰이는데
object-fit : "contail" -> 이미지를 부모영역에 맞게 stretch(늘린다)
object-fit : "cover" -> 이미지를 부모영역에 맞게 crop(자른다)

size

사이즈는 모바일/테블릿/데스크탑 등 각기 다른 너비값을 가진 스크린 환경에서 미리 사이즈를 명시한 후
적합한 이미지를 가져올 수 있도록 해주는 속성입니다.

만일 데스크탑 디스플레이를 위해 디자인된 이미지를
모바일에서 가져와서 쓴다면 너무 불필요하게 큰 파일을 다운로드 하게 되겠죠.

그럴때 아래와 같이 중단점을 기준으로 사이즈를 명시해주면 적합한 사이즈의 이미지를
선택해서 가져올 수 있습니다.

quality

최적화된 이미지의 퀄리티입니다. 1~100까지 숫자로 지정할 수 있고, 디폴트는 75입니다.
100이 가장 좋은 품질(=가장 큰 사이즈의 파일)을 의미함

priority

해당 속성을 가진 이미지는 Lazy loading 방식에서 예외로 처리되고 가장 먼저 preload됩니다.

placeholder

이미지가 로딩될 때 미리 영역을 확보해주는 역할을 합니다.(Layout shift 방지)
"blur"를 사용할 수 도 있고
리모트 이미지나 로컬 이미지를 사용할수도잇음

적용하기

예시 이미지(와이즐리 사이트에서 가져옴)

좌우로 여백이 많은 rectangle 형태의 이미지 파일입니다.

3개의 케이스를 적용해봤는데요.
영상을 보시면 차이점을 아실 수 있을겁니다.

{/* case 1 */}
<div className="test-border">
  <Image src={testimage} alt="recommend" />
</div>

{/* case 2 */}
<div className="tw-relative tw-h-36 test-border">
  <Image
  	src={testimage}
    alt="recommend"
    fill
    style={{ objectFit: "contain" }}
  />
</div>

{/* case 3 */}
<div className="tw-relative tw-h-36 test-border">
  <Image
  	src={testimage}
    alt="recommend"
    fill
    style={{ objectFit: "cover" }}
  />
</div>

브라우저의 width값 변화에 따른 이미지 출력은
case 3 (object-fit: "cover")을 사용했을 때가 가장
자연 스러워 보입니다.

실제 사이트에서도 넥스트는 아니지만
같은 속성이 적용되어 있는걸 볼 수 있었습니다.

다만 갤럭시 폴드의 경우에는 디바이스 너비가 워낙 작아서(반으로 접혔을 때)
이미지가 조금 잘리는 현상이 발생했는데,

이건 실제 레퍼런스 서비스에서도 마찬가지 였습니다.

현재는 이미지를 관리하는 서버(스토리지)가 없어서,
static files를 사용하는 상태기 때문에 최적화 관련해서 크게 적용할 부분이 없네요.

외부서버/CDN을 통해 이미지를 가져오게 된다면 next/image의 priority, 스크린 크기에 따른 size속성 지정 등 신경써야 할 부분이 많을 것 같습니다.

캐루셀과 Grid를 사용하여 메인페이지의 스타일을 비슷하게 만들어 보았습니다.
이번 포스팅은 UI를 똑같이 구현하는게 목적이 아니므로 100% 동일하지 않은 점은 이해해주세요 :)

다음편에 더 알아보도록 하겠습니다.

감사합니다.

profile
여러 고민의 흔적

0개의 댓글