개발 이야기3분 읽기

이미지를 data URI로 넣으면 얼마나 커지나

base64는 33% 늘리고 압축으로도 되돌아오지 않습니다. 파일을 텍스트에 담을 때의 비용을 실측했습니다.

작은 아이콘을 CSS에 직접 넣으면 요청 하나가 줄어듭니다.

background-image: url('data:image/png;base64,iVBORw0KG...');

무엇을 주고 무엇을 받는지 재 봤습니다.

33%가 하한이다

     1바이트 →      4자  (300.0% 증가)
     2바이트 →      4자  (100.0% 증가)
     3바이트 →      4자  ( 33.3% 증가)
   1024바이트 →   1368자  ( 33.6% 증가)
 102400바이트 → 136536자  ( 33.3% 증가)

base64는 3바이트를 4자로 바꿉니다. 4/3 = 33.3%가 늘어나는 양이고, 이것이 하한입니다.

입력이 3의 배수가 아니면 패딩이 붙어 조금 더 커집니다. 작은 파일일수록 비율이 나쁩니다 — 1바이트를 넣으면 4자가 나옵니다.

20KB PNG를 data URI로 만들면 27,330자입니다.

압축해도 돌아오지 않는다

"어차피 gzip이 걸리니 상관없다"가 흔한 반론입니다. 재 봤습니다.

이미 압축된 파일(JPEG·PNG처럼 압축률이 없는 데이터)을 흉내 낸 경우입니다.

원본            30,720 → gzip 30,748
base64로 감싼 것  40,960 → gzip 31,050

gzip 후 차이가 1.0%로 줄었습니다. 원본이 압축되지 않는 데이터라 gzip이 헤더만 붙이고 끝나기 때문입니다 — 원본조차 gzip 후 28바이트 늘었습니다.

반복이 많은 텍스트라면 결과가 다릅니다.

원본 텍스트      30,800 → gzip    168
base64로 감싼 것  41,068 → gzip    359

gzip 후 2.1배로 나빠졌습니다.

base64가 3바이트 단위로 자르는데 텍스트의 반복 주기는 3의 배수가 아니라서, 같은 문장이 반복돼도 base64 출력에서는 서로 다른 문자열이 됩니다. 압축기가 찾을 반복이 사라집니다.

캐시가 더 큰 비용

크기보다 이쪽이 큽니다.

이미지를 파일로 두면 브라우저가 한 번 받아서 오래 캐시합니다. 해시가 들어간 파일명을 쓰면 max-age=31536000, immutable을 걸 수 있습니다.

data URI로 넣으면 그 이미지는 HTML이나 CSS의 일부가 됩니다. 그 문서의 수명을 따라가고, 문서가 바뀔 때마다 이미지도 다시 전송됩니다. CSS 한 줄을 고쳐도 인라인된 이미지 전부가 다시 내려갑니다.

그래도 인라인이 나은 자리

요청 하나의 비용이 파일 크기보다 클 때입니다.

  • 수백 바이트짜리 아이콘. 33% 증가가 절대량으로 작습니다
  • 첫 화면 렌더를 막는 이미지. 별도 요청이 왕복 지연을 더합니다
  • HTTP/1.1 환경. 연결당 동시 요청이 제한됩니다

HTTP/2 이후로는 세 번째 이유가 약해졌습니다. 한 연결에 여러 요청이 다중화되므로 요청 수 자체의 비용이 낮습니다.

SVG라면 base64를 거치지 않고 URL 인코딩으로 넣는 편이 작습니다. SVG는 텍스트라 그대로 넣을 수 있습니다.

반대 방향

base64 문자열을 파일로 되돌리는 일도 자주 있습니다. API 응답에 파일이 base64로 들어 있거나, 이메일 첨부를 꺼낼 때입니다.

이때 확인할 것은 데이터 URI 접두사입니다. data:image/png;base64,까지 포함된 문자열을 그대로 디코딩하면 앞부분이 쓰레기 바이트가 됩니다. 쉼표 뒤부터가 실제 데이터입니다.

확인 순서

  1. 인라인할 이미지의 크기를 봅니다. 수 KB를 넘으면 파일로 두는 편이 대체로 낫습니다
  2. 그 이미지가 자주 바뀌는 문서에 들어가는지 봅니다. 문서가 바뀌면 이미지도 다시 전송됩니다
  3. SVG는 base64 대신 URL 인코딩으로 넣습니다
  4. base64 문자열을 디코딩할 때 data:..., 접두사를 잘라 냈는지 확인합니다
  5. 전송 압축이 켜져 있어도 base64 증가분이 전부 회수되지는 않습니다. 텍스트일수록 손해가 큽니다

tools.onuel.dev파일 Base64 변환은 파일을 base64 문자열이나 data URI로 만들고, 반대로 base64를 내려받을 수 있는 파일로 되돌립니다. 위의 크기 차이를 직접 넣어 확인할 수 있습니다. 텍스트만 다룰 때는 Base64 인코딩디코딩을 쓰고, 바이트를 직접 보려면 Hex 덤프가 있습니다. 압축률을 비교하려면 Gzip에서 같은 데이터를 넣어 볼 수 있습니다.

  • #Base64
  • #성능
  • #