-
NextJS Image태그를 활용한 스켈레톤(Skeleton)처리Next.js 2022. 4. 21. 18:18728x90
스켈레톤(Skeleton)의 필요성
개인적인 생각으로 웹에서 사용자 관점에서 가장 완성도가 떨어져 보이는 요소는 과도한 Layout Shift라고 생각한다.
그렇기에 프로젝트를 진행할 때 스켈레톤 적용에 무척 긍정적이며 더 나아가 꼭 적용해야 되는 요소라고 생각한다.
NextJS Image에서의 처리 방법
그런 점에서 NextJS의 Image태그에는 loading을 blur 처리할 수 있다.
하지만 외부에서 가지고 오는 동적 이미지의 경우 blur 처리하기 위해서는 blurDataURL속성을 입력하라고 되어 있다.
그리고 해당 내용에 대해 NextJS의 공식 Docs에서는 plaiceholder를 사용하는 것을 추천한다.
내가 사용할 방법은 아니지만 해당 방법의 로직을 간단하게 설명하자면 이런 방식이다.
import * as React from "react"; import type { InferGetStaticPropsType } from "next"; import Image from "next/image"; import { getPlaiceholder } from "plaiceholder"; export const getStaticProps = async () => { const { base64, img } = await getPlaiceholder("/path-to-your-image.jpg"); return { props: { imageProps: { ...img, blurDataURL: base64, }, }, }; }; const Page: React.FC<InferGetStaticPropsType<typeof getStaticProps>> = ({ imageProps, }) => ( <div> <Image {...imageProps} placeholder="blur" /> </div> ); export default Page;
이는 Plaiceholder의 사용법 중 base64를 활용하는 방식이다.
위 방법은 Plaiceholder에서 설명하고 있는 방법으로 해당 방법을 사용한다면 내가 불러오는 이미지를 정확하게 blur 처리해서 보여준다.
하지만 실제 우리가 프로젝트를 진행할 때 많이 사용되는 순서는 조금 다르다.
접속 > 기본 스켈레톤 처리 > 불러오려는 글들의 썸네일 이미지를 먼저 getServersideProps 등을 활용해 먼저 불러옴 > Plaiceholder의 로직을 활용해 이미지 blur이미지 생성 > 실제 데이터로 교체
위와 같은 방법으로 구성된다.
물론 모든 데이터를 같이 불러온 뒤 처리해도 되지만, 로드하는데 오래 걸리는 이미지와 blur 된 이미지로 처리되는 시간을 생각했을 때 미리 불러오는 것이 더 나은 방식이라고 생각했다.
위와 같은 방식에서 조금 더 좋게 처리한다면 getStaticProps를 사용하고 이번에 새롭게 나온 ISR을 적용하는 방법도 있다.
실제 사용하는 방법
물론 위와 같은 방법을 사용하는 것이 가장 완성도 높은 모습을 보일 수 있을 것이다.
하지만 실제 프로젝트를 할 때는 시간 대비 엄청난 효율이 나오지 않는다고 생각한다.
그래서 나는 위의 방법 중 base64를 사용할 수 있다는 것에서 착안해 방법을 고안했다.
실제 리스트를 로드할 때의 방법은 아래와 같다.
접속 > 기본 스켈레톤 여러 개 생성 > 데이터 불러옴 > 실제 데이터로 교체
위 정도만 하더라도 꽤나 완성도 있는 결과물이다.
하지만 실제 데이터로 변경하는 과정에서 이미지의 로딩은 텍스트에 비해 느리기에 blurDataURL을 사용하는 것이다.
그래서 나는 Next Image태그의 blurDataURL에 스켈레톤 이미지와 동일한 색상의 base64 데이터를 생성한 뒤 고정값으로 넣어주는 것으로 처리했다.
색상 base64를 생성하는 사이트의 경우 나는 png-pixel이라는 사이트를 활용했다.
스켈레톤 이미지와 같은 색상값을 넣은 뒤 opacity를 1로 사이즈는 10x10를 사용해 생성할 수 있다.
(주의해야 될 점으로 blurDataURL의 경우 10x10 이상의 사이즈가 될 경우 성능 저하될 위험이 있다고 경고가 나온다.)
아래는 내가 사용한 간단한 예시이다.
import React from "react"; import Image from "next/image"; interface IProps{ src: string; } const blurDataURL = 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFklEQVR42mN8//HLfwYiAOOoQvoqBABbWyZJf74GZgAAAABJRU5ErkJggg=='; const WithSkeletonImage: React.FC = ({src}) => ( <div> <Image src={src} alt="test" width="200px" height="200px" placeholder="blur" blurDataURL={blurDataURL} /> </div> ); export default WithSkeletonImage;
그리고 vercel deploy의 특성일 수 있는데 blurDataURL의 이미지를 출력한 뒤 동적 이미지의 blur를 간단하게 보여준 뒤 실제 이미지로 변경해 주는 소소한 장점이 있다.
적용 전
적용 후
위의 데이터는 실제로 본다면 크게 긴 시간은 아니다.
하지만 이런 디테일을 통해 완성도가 올라간다고 생각하며 위와 같은 방법은 생각보다 간단하니 실제 프로젝트에 적절하게 적용해보기를 바란다.
(해당 글은 NextJS@12.1을 기반으로 작성되었으며 불러온 동적 이미지는 antd의 공개 이미지를 사용하였습니다.)
'Next.js' 카테고리의 다른 글
NextJS Babel에서 SWC로 이사가기 2 (2) 2022.05.20 NextJS Babel에서 SWC로 이사가기 1 (1) 2022.05.17 NextJS Cypress 설정하기 (0) 2022.02.17 NextJS Image 태그 height auto로 사용하기 (0) 2022.01.11 NextJS + Redux-Toolkit + next-redux-wrapper 설정하기 (0) 2021.09.24