Base64 이미지, 왜 원본보다 정확히 33% 커지나
이미지를 Base64로 인코딩하면 "대략" 커지는 게 아니라 정확히 4/3배(약 33.3%) 커집니다. 이건 근사치가 아니라 인코딩 방식 자체에서 나오는 수학적으로 고정된 값입니다. 이 가이드는 왜 하필 33%인지, 그리고 이 오버헤드를 감수할 가치가 있는 상황과 절대 쓰면 안 되는 상황을 구분해서 정리합니다.
1. 왜 하필 33%인가: 6비트와 8비트의 차이
원본 바이너리 파일은 1바이트당 8비트, 즉 256가지 값을 표현합니다. 하지만 Base64는 결과를 사람이 읽고 텍스트로 안전하게 전송할 수 있는 ASCII 문자(A-Z, a-z, 0-9, +, /) 64개로만 표현해야 합니다. 64가지 값을 구분하는 데 필요한 비트 수는 log2(64) = 6비트뿐입니다. 그래서 Base64는 원본을 8비트가 아니라 6비트 단위로 잘라서, 그 6비트 조각 하나를 ASCII 문자 1개(=8비트로 저장되는 텍스트 1글자)에 담습니다.
즉 원본 3바이트(24비트)는 정확히 4개의 6비트 조각으로 나뉘고, 이 4조각이 각각 텍스트 문자 1개(8비트)가 되어 총 4바이트의 텍스트로 저장됩니다. 3바이트 → 4바이트, 이 비율이 정확히 4/3 = 1.3333...이고, 이게 33.3% 증가의 정체입니다. 8비트를 6비트로 쪼개 담는 대가로 "저장 밀도"가 25% 손해(8비트 중 6비트만 활용)를 보고, 그 손해가 최종 출력 크기에서는 33% 증가로 나타나는 구조입니다.
2. 정확한 계산 공식과 실측 예시
원본이 정확히 3의 배수 바이트가 아니면 마지막에 패딩 문자(=)가 1~2개 붙어 4의 배수 길이를 맞춥니다. 공식은 다음과 같습니다.
예: 1,000,000바이트(약 1MB) 이미지 → ceil(1,000,000/3) × 4 = 333,334 × 4 = 1,333,336바이트(약 1.27MiB)
여기에 Data URL로 쓰려면 data:image/png;base64, 같은 접두사(약 20~30바이트)까지 추가로 붙습니다. 미미한 수준이라 전체 오버헤드에는 거의 영향을 주지 않지만, 텍스트 데이터로 저장·전송된다는 점에서 원본 바이너리와는 근본적으로 다른 형태가 됩니다.
3. 그럼에도 Base64를 쓰는 게 이득인 경우
33% 손해를 감수하고도 Base64 인라인이 유리한 상황이 있습니다.
- 작은 아이콘·스프라이트: 파일 자체가 1~2KB 수준이면 33% 증가는 몇백 바이트에 불과합니다. 반면 별도 파일로 두면 HTTP 요청 1개가 추가되는데, 특히 HTTP/1.1 환경에서는 요청당 지연(latency)이 용량 증가보다 체감 손해가 큽니다.
- 단일 HTML 파일 배포: 이메일 템플릿, 오프라인 리포트, 설치 없이 공유하는 문서처럼 "파일 하나로 완결"되어야 하는 상황에서는 외부 이미지 파일 자체가 존재할 수 없으므로 Base64가 유일한 선택지입니다.
- Critical CSS의 인라인 배경 이미지: 렌더링 차단 없이 최초 화면에 바로 그려야 하는 매우 작은 배경 이미지는 별도 요청을 아예 없애는 편이 낫습니다.
4. 절대 쓰면 안 되는 경우: 캐싱을 잃는다는 게 진짜 손실
사진처럼 큰 이미지를 Base64로 인라인하면 33% 용량 증가보다 훨씬 치명적인 손실이 따로 있습니다. 바로 브라우저 캐싱을 잃는다는 점입니다. 별도 이미지 파일(.jpg, .png 등)은 HTTP 캐시 헤더에 따라 브라우저가 저장해뒀다가 재방문 시 재다운로드하지 않습니다. 하지만 Data URL은 HTML이나 CSS 문서 안에 텍스트로 박혀 있기 때문에, 그 이미지만 따로 캐시되는 게 아니라 부모 문서(HTML/CSS)가 캐시되거나 갱신될 때마다 통째로 다시 다운로드됩니다. 즉 방문할 때마다, 또는 CSS 파일을 한 글자만 고쳐도 그 안에 박힌 모든 이미지를 다시 받아야 하는 셈입니다.
또한 큰 Base64 문자열은 HTML/CSS 파서가 처리해야 할 문서 크기 자체를 키워 파싱·렌더링 지연을 유발하고, gzip/brotli 압축 효율도 원본 바이너리 이미지 압축(JPEG/PNG 자체 압축)보다 떨어지는 경우가 많습니다.
5. 실무 기준: 어디까지가 "작은" 이미지인가
업계에서 통용되는 대략적인 기준선은 다음과 같습니다. 절대적 규칙은 아니지만 판단 기준으로 삼기에 무난합니다.
| 원본 크기 | 권장 | 이유 |
|---|---|---|
| ~2KB 이하 | Base64 인라인 무난 | 요청 절약 효과 > 33% 오버헤드+캐시 손실 |
| 2KB~10KB | 상황에 따라 판단 | 사용 빈도(반복 노출 여부)에 따라 갈림 |
| 10KB 이상 | 별도 파일 권장 | 캐시 손실 효과가 요청 절약 효과를 압도 |
HTTP/2·HTTP/3가 보편화되면서 "요청 수 자체를 줄여야 한다"는 과거의 압박은 많이 완화됐습니다. 멀티플렉싱 덕분에 요청 여러 개를 병렬로 받는 비용이 낮아졌기 때문에, 최근에는 특별한 이유가 없다면 사진·큰 이미지는 별도 파일로 두고 캐싱 이점을 살리는 쪽이 대체로 더 유리합니다.
자주 묻는 질문
Q. 33%는 어떤 이미지든 항상 정확히 33%인가요?
네, 인코딩 원리 자체가 원본 3바이트를 텍스트 4바이트로 바꾸는 구조라 파일 형식(PNG/JPEG/WebP)과 무관하게 항상 정확히 4/3배입니다. 다만 3으로 나누어떨어지지 않는 나머지 부분에 패딩(=)이 붙어 아주 미세하게(최대 2바이트) 더 커질 수 있습니다.
Q. gzip으로 압축하면 33% 손해를 상쇄할 수 있나요?
부분적으로만 가능합니다. Base64 텍스트는 원본 바이너리 이미지(이미 JPEG/PNG 자체 압축이 적용된 상태)보다 패턴이 반복되긴 하지만, gzip이 이미지 데이터 자체를 다시 잘 압축하지는 못합니다. 오버헤드를 완전히 없애지는 못합니다.
Q. Data URL과 순수 Base64 문자열, 크기 차이가 있나요?
Data URL은 data:image/png;base64, 같은 접두사(MIME 타입 표기)가 20~30바이트 정도 추가로 붙습니다. 전체 크기에 비하면 미미하지만, 아주 작은 아이콘에서는 비율상 무시할 수 없을 수도 있습니다.
Q. SVG도 Base64로 인코딩하면 33% 커지나요?
네, 동일합니다. 다만 SVG는 텍스트 기반 포맷이라 Base64 대신 URL 인코딩(data:image/svg+xml,...)으로 삽입하면 오버헤드를 줄일 수 있는 경우가 많습니다.