NextJS의 blurDataURL과 base64

Inhwa Lee·2022년 9월 13일
0

Performance

목록 보기
2/2

서론

Next JS 프로젝트 중 이미지 최적화 과정에서 Next JS에서 제공하는 blurDataURL을 사용해 이미지가 로딩되는 동안 사용자에게 보여줄 플레이스 홀더를 구현하기로 했다.

Next JS를 사용해 랜딩 페이지를 제작하는데, 시안에 이미지가 많이 사용되고 있었을 뿐더러 모든 페이지에서 처음 보여지는 화면이 풀페이지 디자인이여서 SSR 임에도 불구하고 첫 페이지 접속시 빈 화면이 보여지는 문제가 있었다. Next JS는 이미지 최적화를 위해 레이지 로딩, 사이즈 최적화 등 여러 기능을 지원하고 있는데, 그 중 이미지가 로딩되기 전까지 블러 이미지를 띄워주는 blurDataURL 속성을 사용해 사용자에게 이미지가 로딩 중임을 알려주고, 원본 이미지를 추측할 수 있도록 개선하기로 했다.

Next JS 이미지 플레이스 홀더 데모 →

blurDataURL 사용 방법

placeholder 속성에 이미지 플레이스 홀더를 어떻게 처리할지 적어준다. 기본값은 empty 이다. blurDataURL 속성에는 base64로 인코딩된 10px 이하의 데이터 URL을 적어준다. 10px 이하인 이유는 작은 픽셀의 이미지 크기를 키우는 방식으로 블러 처리하기 때문이다.

const base64 = 'data:image/jpeg;base64,'
const blurImg = 'base64로 인코딩되서 ASCII 문자열로만 이루어진 이미지 데이터'

<Image
  src='./logo.jpg'                 // 실제 보여줄 이미지 URL
  alt='로고'    
  layout='fill'                    // 부모의 넓이와 높이를 따름
  objectFit='cover'                // 사이즈를 부모에 맞춰 꽉 채움
  placeholder='blur'               // 이미지 플레이스 홀더 처리 방식
  blurDataURL={base64 + blurImg}   // base64로 인코딩된 플레이스 홀더 데이터 URL 
/>

왜 base64 인코딩을 사용하는가?

이미지를 base64로 인코딩하면 인코딩 결과인 문자열이 이미지 데이터 자체이므로 이미지를 가져오기 위해 별도의 데이터 통신을 하지 않아도 된다.

브라우저는 HTML을 파싱하다가 img 같이 외부 파일을 불러와야 하는 코드를 만나면 별도의 네트워크 통신을 통해 해당 파일을 가져오는 작업을 한다. 이 때 이미지가 용량이 크거나 네트워크 통신이 원활하지 않으면 사용자는 사진이 불러와질 때까지 계속 빈 화면을 보게 될 것이다.

base64란 8비트(2^8) 이진 데이터를 문자 코드에 영향을 받지 않는 공통 ASCII 영역의 문자들로만 이루어진 문자열로 바꾸는 인코딩 방식이다. 글자 그대로 번역하면 64진법(2^6)이라는 뜻으로 ASCII 문자 중 총 64개 (A-Z, a-z, 0–9, /+)를 사용하여 문자열을 구성한다.

즉, base64를 이용하면 문자 포맷이 달라 데이터를 손상시키는 위험 없이 HTML 파일에 이미지 데이터를 담아 안전하게 전송할 수 있다. 그렇게 전송된 이미지 데이터는 그 자체가 데이터이므로 HTML 파싱 과정에서 이미지 태그를 발견하더라도 이미지를 불러오기 위한 별도의 데이터 통신을 하지 않고 보여주기만 하면 된다.

여기까지 보면 모든 이미지를 애초에 base64로 인코딩해서 처리하면 네트워크 통신 횟수도 줄고, 이미지도 빨리 보여줄 수 있으니 좋지 않을까? 하는 생각이 들 수도 있다. 결론은 '안된다' 이다. base64는 인코딩 과정에서 용량을 약 30% 더 키운다는 단점이 있다. 아래 base64 인코딩 과정을 통해 어떻게 용량이 늘어나는지 알아보자.

base64 인코딩 과정

8비트 이진 데이터를 6비트 단위로 나눈 후 부족한 부분은 0으로 채워 자릿수를 보정하고, base64 코드표를 통해 64개 중 매칭되는 문자로 변환한다. 6bit를 4개씩 모아 변환해야 하므로 부족한 공간은 패딩문자 = 로 채운다.

진법변환에 대해 안다면 간단한 문자 정도는 별다른 도구의 도움 없이 직접 base64 인코딩 해볼 수 있다. 과정을 이해하기 위한 예시이므로 수백 수천개의 이진 데이터로 구성된 이미지 말고 bear라는 짧은 단어로 base64 인코딩을 진행해보려고 한다.

1. ASCII 코드표를 참조해 각 문자를 16진수(2^4)로 변환한다. (영문 문자 하나는 8비트이므로 2개의 숫자가 나옴)

  • b => 62
  • e => 65
  • a => 61
  • r => 72

2. 16진수로 변환한 문자를 이진 데이터로 변환한다. (이제 base64로 인코딩하기 위한 기본 모양 8비트 이진 데이터가 되었다.)

  • b => 62 => 0110 0010
  • e => 65 => 0110 0101
  • a => 61 => 0110 0001
  • r => 72 => 0111 0010

3. 변환한 이진 데이터를 한줄로 합친 후 6비트 단위로 나눠준다. (base64는 64진법(2^6)이므로 문자 하나를 6비트로 표현한다.)
011000 100110 010101 100001 011100 10

4. 부족한 부분은 0으로 채워 자릿수를 보정한다.
011000 100110 010101 100001 011100 100000

5. base64 코드표를 통해 매칭되는 문자로 변환한다.
YmVhcg

6. base64는 6bit를 4개씩 모아 변환해야 하므로 부족한 공간은 패딩문자 = 로 채운다.
YmVhcg==

base64 인코딩 도구

window 객체 메서드인 btoa()atob()를 사용해 인코딩, 디코딩 할 수도 있고, 이미 잘 만들어진 라이브러리나 서비스들을 이용할 수도 있다. 나는 base64-image를 사용해서 변환했다.

const a = btoa('bear');      // 'YmVhcg=='
const b = atob('YmVhcg==');  // 'bear'

참고

profile
Frontend Developer

0개의 댓글