스타일시트 안에 써 넣은 이미지는 스타일시트와 함께 도착합니다. 두 번째 요청도, 기다림도 없습니다. 대신 더 이상 파일이 아니게 되지요. 따로 캐시될 수 없고, 둘레의 무엇이 바뀔 때마다 통째로 다시 내려받습니다. 그 거래가 값어치 있는 자리와, 조용히 손해가 되는 자리를 정리했습니다.
# 스타일시트 안에 그림을 넣어야 할 때와 넣지 말아야 할 때
스타일시트 안에 써 넣은 이미지는 스타일시트와 함께 도착합니다. 두 번째 요청도, 기다림도 없습니다. 대신 더 이상 파일이 아니게 되지요. 따로 캐시될 수 없고, 둘레의 무엇이 바뀔 때마다 통째로 다시 내려받습니다. 그 거래가 값어치 있는 자리와, 조용히 손해가 되는 자리를 정리했습니다.
[이미지를 데이터 URI로 열기](https://abox.tools/ko/이미지-base64-변환/): 사진 전체를 텍스트 한 줄로. CSS나 HTML에 그대로 붙여 넣으세요.
마지막 업데이트 2026년 8월 26일
## 짧은 답
[이미지를 데이터 URI로](https://abox.tools/ko/이미지-base64-변환/)를 열고 그림을 넣은 다음 *CSS 사용자 지정 속성*을 고르고, 그 줄을 스타일시트 맨 위에 붙여 넣으세요. 그다음 필요한 곳마다 `background-image: var(--logo)`로 쓰시면 됩니다.
아이콘이나 불릿, 화살표, 패턴처럼 그림이 작고 모든 페이지에 필요할 때 그렇게 하세요. 사진에는 하지 마세요. 아래는 그 두 문장이 왜 다른지, 그리고 지금 보고 계신 것이 어느 쪽인지 어떻게 아는지에 대한 것입니다.
## 데이터 URI가 실제로 무엇인지
가리키는 대신 담고 있는 주소입니다. 스타일시트가 보통 이렇게 적고
```
background-image: url("logo.png");
```
브라우저가 가서 `logo.png`를 가져오는 자리에, 데이터 URI는 이렇게 적습니다
```
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...");
```
그리고 가져올 것이 없습니다. 그림이 이미 거기, 글자로 적혀 있으니까요. 세 부분으로 이루어집니다. `data:`는 스킴입니다. `image/png`는 미디어 타입이고, 브라우저는 그것을 완전히 믿습니다. 그 이야기는 아래에 더 있습니다. 쉼표 뒤가 전부 파일이고요.
발상은 그게 전부입니다. 꼼수도 편법도 아닙니다. 1998년부터 표준에 들어 있었고, 그 뒤에 나온 모든 브라우저에서 동작합니다.
## 얻는 것: 왕복 한 번
아끼는 것은 대역폭이 아니라 요청입니다.
브라우저는 `logo.png`를 언급하는 스타일시트를 읽기 전에는 그것을 요청할 수 없고, 그 스타일시트를 가져오기 전에는 읽을 수 없습니다. 그래서 평범한 배경 이미지는 페이지 로딩에서 최소 두 번의 왕복만큼 깊이 있고, 느린 회선의 휴대폰에서는 파일이 아무리 작아도 왕복 한 번이 200밀리초쯤 될 수 있습니다. 600바이트짜리 화살표는 전송에 거의 아무 비용도 들지 않으면서도 도착하는 데 4분의 1초를 쓸 수 있습니다.
인라인으로 넣으면 스타일시트와 함께 도착합니다. 이득은 그게 전부이고, 화면 첫 화면에 나타나는 작은 아이콘이라면 진짜 이득입니다.
## 치르는 것: 3분의 1, 그리고 캐시
**base64는 3분의 1쯤을 더합니다.** 파일 3바이트가 4글자가 되는데, URL이 허용하는 문자만으로 임의의 바이트를 적어 내는 데 드는 비용이 그것입니다. 그것을 피하는 영리한 인코더는 없습니다. 9KB짜리 PNG는 스타일시트 12KB입니다.
**압축이 그것을 돌려주지는 않습니다.** 사람들이 당연하게 넘겨짚는 대목입니다. gzip과 Brotli는 중복을 찾아내는 방식으로 일하는데, PNG와 JPEG와 WebP는 이미 압축되어 있습니다. 남은 중복이 거의 없고, base64가 중복을 만들어 주지도 않습니다. 실제로는 base64가 더한 3분의 1 중 10분의 1쯤을 돌려받지, 전부를 돌려받지는 못합니다. (SVG는 반대 경우이고, 다음 절이 그 이야기입니다.)
**더 이상 파일이 아니게 됩니다.** 재 볼 만한 어떤 측정에도 잡히지 않는 대가이고, 크기가 커질수록 중요해지는 그것입니다.
- **따로 캐시될 수 없습니다.** 평범한 이미지는 한 번 가져와 1년 동안 재사용됩니다. 인라인된 것은 스타일시트의 일부라, 스타일시트의 캐시 항목과 운명을 같이합니다.
- **무엇이든 바뀌면 전부 다시 내려받습니다.** 여백 하나 고쳐 새 스타일시트를 배포하면, 모든 방문자가 그와 함께 인라인된 그림도 다시 내려받습니다. 2년 동안 바뀌지 않은 그림을요.
- **임계 경로에 놓입니다.** 스타일시트는 렌더링을 막습니다. 이미지는 막지 않습니다. 그림을 인라인으로 넣는다는 것은 그것을 두 번째 범주에서 첫 번째로 옮긴다는 뜻입니다. 그림까지 포함해 전부 도착하기 전에는 페이지가 그려지지 못합니다.
- **병렬로 받아 올 수 없습니다.** 브라우저는 여러 가지를 한 번에 내려받습니다. 인라인된 그림은 별개의 것이 아니라서 그 혜택을 하나도 받지 못합니다.
대략의 경계선인데, 브라우저가 무언가 다르게 하는 지점이 아니라 조언이 바뀌는 지점입니다. 2KB쯤 아래면 분명한 이득이고, 10KB쯤까지는 모든 페이지에 나오는 것이라면 대체로 값어치가 있으며, 50KB를 넘으면 오류 메시지 없는 실수입니다. [이 도구](https://abox.tools/ko/이미지-base64-변환/)는 각 결과가 어느 구간에 떨어지는지를 글자 수와 함께 알려 줍니다.

인코딩한 사본은 원래 파일보다 3분의 1쯤 커집니다. 이 절이 다루는 대가가 그것이고, 알아서 발견하도록 두지 않고 적어 두었습니다.
## SVG를 base64로 만들지 마세요
인라인 이미지에서 가장 흔한 실수 하나이고, 사람만큼이나 내보내기 도구와 빌드 플러그인도 자주 저지릅니다.
SVG는 텍스트입니다. URL은 이미 텍스트를 실어 나릅니다. 이스케이프해야 하는 문자는 `%`, `#`, `<`, `>`, 그리고 감쌀 때 쓴 따옴표 정도뿐이고, 나머지는 있는 그대로 두어도 됩니다. 그렇게 인코딩하면 같은 파일의 base64 보다 대개 5분의 1쯤 짧은 URI가 나오고, 그 뒤로도 잡음이 아니라 텍스트처럼 압축됩니다.
게다가 여전히 읽힙니다.
```
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E...");
```
`viewBox`가 보입니다. 아무것도 디코딩하지 않고 편집기에서 채움 색을 바꿀 수 있습니다. 같은 파일을 base64로 만들면 아무도 다시는 손대지 않을 글자의 벽이 됩니다. [이미지를 데이터 URI로](https://abox.tools/ko/이미지-base64-변환/)는 SVG로 판별된 것에는 이 방식을 자동으로 쓰고, `;base64`를 고집하는 드문 도구 체인을 위한 체크박스도 있습니다.
## SVG에서만 깨지는 따옴표 실수
CSS는 `url()`을 따옴표 없이 쓰는 것을 허용하고, 평범한 파일 이름이라면 그래도 괜찮습니다.
```
background-image: url(logo.png);
```
퍼센트 인코딩한 SVG에 같은 짓을 하면 깨집니다. 따옴표 없는 `url()` 토큰은 첫 공백이나 괄호, 따옴표, 제어 문자에서 끝나는데 SVG는 속성 사이마다, 경로의 숫자 사이마다 공백으로 가득하고요. 그러면 그 선언이 무효가 되고, CSS는 무효한 선언을 조용히 버립니다. 배경도 오류도 얻지 못하는 것이죠.
해법은 언제나 따옴표입니다.
```
background-image: url("data:image/svg+xml,%3Csvg ... %3E");
```
인코더가 공백을 이스케이프하지 않아도 되는 이유이기도 합니다. 따옴표로 감싼 URL 안에서 공백은 완벽히 적법하고, 하나하나를 `%20`으로 바꾸면 파일 속 공백마다 3글자를 더 쓰게 됩니다. 두 결정은 짝입니다. URI에 따옴표를 씌우면 공백은 그대로 두어도 됩니다. 이 도구가 만들어 내는 모든 형태에 따옴표가 씌워져 있는 이유가 정확히 그것입니다.
## 미디어 타입이 맞아야 합니다
데이터 URI는 자기 타입을 스스로 선언하고, 브라우저는 그 말을 곧이곧대로 믿습니다. 가져온 파일에 대해서는 있는 추측 기반의 대비책이 여기에는 없습니다. 실은 JPEG인 것을 `image/png`라고 말하면 그림은 그려지지 않고, 쓸모 있는 어디에도 메시지가 남지 않습니다.
이게 중요한 이유는 파일 확장자가 거짓말을 하기 때문입니다. JPEG로 내보낸 뒤 `logo.png`로 이름이 바뀐 사진은 디스크에서 흔히 볼 수 있는 것입니다. 반면 이미지 파일의 첫 몇 바이트는 그것이 무엇인지를 분명히 말합니다. 모든 형식에 시그니처가 있으니까요. 그러니 도구는 이름이 아니라 파일을 읽어야 합니다. 여기 도구는 그렇게 하고, 둘이 어긋나면 알려 줍니다.
헷갈리는 방식으로 실패하기 때문에 알아 둘 만한 형식이 둘 있습니다. 아이폰이 사진을 찍는 형식인 **HEIC**와 스캐너가 만들어 내는 **TIFF**는 둘 다 완벽히 올바른 데이터 URI를 만들지만 Safari를 뺀 어떤 브라우저도 그리지 않습니다. URI가 망가진 것이 아니라 그 형식이 웹이 지원하는 것이 아닐 뿐입니다. 먼저 변환하세요.
## 공개할 생각이 없었던 메타데이터
데이터 URI는 파일을 바이트 그대로 복사한 것입니다. 디코딩했다가 다시 인코딩하는 일이 없는데, 화질을 잃지 않으니 대개 그게 요점이지요. 다만 파일 안의 그 밖의 모든 것도 함께 온다는 뜻이기도 합니다.
휴대폰에서 막 나온 사진은 EXIF를 싣고 있습니다. 촬영된 자리의 GPS 좌표, 촬영 시각, 카메라 모델, 흔히 그 일련번호까지요. 그것만 파일의 30KB일 수 있습니다. 인라인으로 넣으면 스타일시트 안에서 base64 40KB가 되어 모든 페이지의 임계 경로에 얹힙니다. 그리고 아무도 들여다볼 생각조차 하지 않을 형태로, 저장소에 커밋된 집 주소가 됩니다.
먼저 [EXIF 확인 및 제거](https://abox.tools/ko/exif-정보-삭제/)로 지우세요. 사진을 건드리지 않고 컨테이너만 다시 씁니다. [그에 대한 가이드](https://abox.tools/ko/가이드/사진-위치정보-삭제/)도 있습니다. 이미지를 데이터 URI로는 JPEG, PNG, WebP에 메타데이터가 얼마나 들었는지 읽어, 무엇을 복사하기 전에 알려 줍니다.
## 손에 넣은 다음 어디에 둘지
그림이 규칙 하나에만 나온다면 URI를 그 규칙에 두세요. 여러 곳에 나온다면 사용자 지정 속성으로 한 번만 선언하시고요. 아이콘은 호버 상태와 다크 테마까지 세면 대개 여러 곳에 나옵니다.
```
:root {
--icon-search: url("data:image/svg+xml,%3Csvg ... %3E");
}
.search-field { background-image: var(--icon-search); }
.search-button::before { content: var(--icon-search); }
```
3KB짜리 URI를 네 규칙에 붙여 넣으면 스타일시트 12KB에, 아이콘이 바뀔 때 고칠 자리가 네 곳입니다. 사용자 지정 속성이라면 각각 하나씩입니다. 테마를 가능하게 해 주는 형태이기도 합니다. 미디어 쿼리 안에서 `--icon-search`를 다시 정의하면 그것을 쓰는 모든 곳이 따라옵니다.
CSS가 아니라 `<img>` 태그라면 `width`와 `height`를 넣으세요. 인라인된 이미지는 즉시 불려 오므로, 크기가 빠지면 눈에 보이지 않을 만큼 빠르게 일어나는 레이아웃 이동이 되고 그래도 점수는 깎입니다. 예외는 SVG입니다. `viewBox`만 있는 SVG에는 자기 픽셀 크기가 없는데, 브라우저의 기본값 300×150을 태그에 박아 넣으면 아무도 고르지 않은 크기에 확대 가능한 그림을 못 박는 셈이 됩니다.
`alt`에 넣을 참된 말이 없다면 비워 두세요. 그 그림이 뜻을 담고 있는지 그냥 장식인지는 넣는 사람만 알고, 파일 이름에서 짐작해 붙인 설명은 화면 낭독기를 쓰는 사람에게 설명이 아예 없는 것보다 나쁩니다.

어디로 가는지가 무엇이 나올지를 정하므로, 복사해 붙여넣는 연습으로 남기지 않고 먼저 묻습니다.
## 답이 “하지 마세요”일 때
인코딩했을 때 50KB쯤을 넘는 그림이라면 인라인은 틀린 도구이고, 인코딩을 아무리 조심해도 고쳐지지 않습니다. 시도해 볼 만한 순서대로 대안을 적습니다.
- **작게 만드세요.** 인라인으로 넣기에 너무 큰 이미지는 대부분 그냥 너무 큽니다. [이미지 압축](https://abox.tools/ko/이미지-압축/)이 사진을 말씀하신 용량으로 데려다주고, [이미지 크기 조절](https://abox.tools/ko/이미지-크기-조절/)이 픽셀 치수를 레이아웃이 실제로 쓰는 만큼으로 깎아 줍니다. 진짜 문제가 그것인 경우가 아주 많거든요.
- **SVG로 다시 그리세요.** 40KB짜리 PNG로 내보낸 아이콘이 900바이트짜리 SVG인 경우가 흔합니다. 압축의 차이가 아니라 형식의 차이이고, 레티나 문제까지 함께 풀어 줍니다.
- **파일로 두고 preload 하세요.** `<link rel="preload" as="image">`는 바이트를 임계 경로에 올리지 않고 곧바로 가져오기를 시작합니다. 인라인의 이득 대부분을 얻고 캐시의 대가는 치르지 않습니다.
## 이 중 무엇에도 업로드는 필요 없습니다
파일을 base64로 인코딩하는 것은 산술입니다. 브라우저가 처음부터 갖고 있던 두 함수, `btoa`와 `encodeURIComponent`가 하는 일이고요. 그림을 다르게 적어 내겠다고 서버에 갔다 와야 할 기술적 이유는 털끝만큼도 없습니다. 이 일을 하겠다고 파일을 업로드하는 변환기는 사용자를 위해서가 아니라 자기 이유로 업로드하고 있는 것입니다.
[여기 도구](https://abox.tools/ko/이미지-base64-변환/)는 그것을 어디로도 보내지 않습니다. 페이지의 `Content-Security-Policy`가 연결 가능한 주소를 전부 적어 두는데, 그중 이 사이트의 것은 없습니다. 듣기만 하는 것보다 직접 확인하고 싶다면, 페이지를 불러온 다음 인터넷을 끊고 그냥 인코딩해 보세요. [온라인 변환 사이트에 파일을 올려도 안전할까요?](https://abox.tools/ko/가이드/파일-업로드-안전한가/)에 어떤 도구에든 해 볼 수 있는 확인 세 가지가 더 있습니다.
짧은 답
이미지를 데이터 URI로를 열고 그림을 넣은 다음 CSS 사용자 지정 속성을 고르고, 그 줄을 스타일시트 맨 위에 붙여 넣으세요. 그다음 필요한 곳마다 background-image: var(--logo)로 쓰시면 됩니다.
아이콘이나 불릿, 화살표, 패턴처럼 그림이 작고 모든 페이지에 필요할 때 그렇게 하세요. 사진에는 하지 마세요. 아래는 그 두 문장이 왜 다른지, 그리고 지금 보고 계신 것이 어느 쪽인지 어떻게 아는지에 대한 것입니다.
그리고 가져올 것이 없습니다. 그림이 이미 거기, 글자로 적혀 있으니까요. 세 부분으로 이루어집니다. data:는 스킴입니다. image/png는 미디어 타입이고, 브라우저는 그것을 완전히 믿습니다. 그 이야기는 아래에 더 있습니다. 쉼표 뒤가 전부 파일이고요.
발상은 그게 전부입니다. 꼼수도 편법도 아닙니다. 1998년부터 표준에 들어 있었고, 그 뒤에 나온 모든 브라우저에서 동작합니다.
얻는 것: 왕복 한 번
아끼는 것은 대역폭이 아니라 요청입니다.
브라우저는 logo.png를 언급하는 스타일시트를 읽기 전에는 그것을 요청할 수 없고, 그 스타일시트를 가져오기 전에는 읽을 수 없습니다. 그래서 평범한 배경 이미지는 페이지 로딩에서 최소 두 번의 왕복만큼 깊이 있고, 느린 회선의 휴대폰에서는 파일이 아무리 작아도 왕복 한 번이 200밀리초쯤 될 수 있습니다. 600바이트짜리 화살표는 전송에 거의 아무 비용도 들지 않으면서도 도착하는 데 4분의 1초를 쓸 수 있습니다.
인라인으로 넣으면 스타일시트와 함께 도착합니다. 이득은 그게 전부이고, 화면 첫 화면에 나타나는 작은 아이콘이라면 진짜 이득입니다.
치르는 것: 3분의 1, 그리고 캐시
base64는 3분의 1쯤을 더합니다. 파일 3바이트가 4글자가 되는데, URL이 허용하는 문자만으로 임의의 바이트를 적어 내는 데 드는 비용이 그것입니다. 그것을 피하는 영리한 인코더는 없습니다. 9KB짜리 PNG는 스타일시트 12KB입니다.
압축이 그것을 돌려주지는 않습니다. 사람들이 당연하게 넘겨짚는 대목입니다. gzip과 Brotli는 중복을 찾아내는 방식으로 일하는데, PNG와 JPEG와 WebP는 이미 압축되어 있습니다. 남은 중복이 거의 없고, base64가 중복을 만들어 주지도 않습니다. 실제로는 base64가 더한 3분의 1 중 10분의 1쯤을 돌려받지, 전부를 돌려받지는 못합니다. (SVG는 반대 경우이고, 다음 절이 그 이야기입니다.)
더 이상 파일이 아니게 됩니다. 재 볼 만한 어떤 측정에도 잡히지 않는 대가이고, 크기가 커질수록 중요해지는 그것입니다.
따로 캐시될 수 없습니다. 평범한 이미지는 한 번 가져와 1년 동안 재사용됩니다. 인라인된 것은 스타일시트의 일부라, 스타일시트의 캐시 항목과 운명을 같이합니다.
무엇이든 바뀌면 전부 다시 내려받습니다. 여백 하나 고쳐 새 스타일시트를 배포하면, 모든 방문자가 그와 함께 인라인된 그림도 다시 내려받습니다. 2년 동안 바뀌지 않은 그림을요.
임계 경로에 놓입니다. 스타일시트는 렌더링을 막습니다. 이미지는 막지 않습니다. 그림을 인라인으로 넣는다는 것은 그것을 두 번째 범주에서 첫 번째로 옮긴다는 뜻입니다. 그림까지 포함해 전부 도착하기 전에는 페이지가 그려지지 못합니다.
병렬로 받아 올 수 없습니다. 브라우저는 여러 가지를 한 번에 내려받습니다. 인라인된 그림은 별개의 것이 아니라서 그 혜택을 하나도 받지 못합니다.
대략의 경계선인데, 브라우저가 무언가 다르게 하는 지점이 아니라 조언이 바뀌는 지점입니다. 2KB쯤 아래면 분명한 이득이고, 10KB쯤까지는 모든 페이지에 나오는 것이라면 대체로 값어치가 있으며, 50KB를 넘으면 오류 메시지 없는 실수입니다. 이 도구는 각 결과가 어느 구간에 떨어지는지를 글자 수와 함께 알려 줍니다.
인코딩한 사본은 원래 파일보다 3분의 1쯤 커집니다. 이 절이 다루는 대가가 그것이고, 알아서 발견하도록 두지 않고 적어 두었습니다.
SVG를 base64로 만들지 마세요
인라인 이미지에서 가장 흔한 실수 하나이고, 사람만큼이나 내보내기 도구와 빌드 플러그인도 자주 저지릅니다.
SVG는 텍스트입니다. URL은 이미 텍스트를 실어 나릅니다. 이스케이프해야 하는 문자는 %, #, <, >, 그리고 감쌀 때 쓴 따옴표 정도뿐이고, 나머지는 있는 그대로 두어도 됩니다. 그렇게 인코딩하면 같은 파일의 base64 보다 대개 5분의 1쯤 짧은 URI가 나오고, 그 뒤로도 잡음이 아니라 텍스트처럼 압축됩니다.
viewBox가 보입니다. 아무것도 디코딩하지 않고 편집기에서 채움 색을 바꿀 수 있습니다. 같은 파일을 base64로 만들면 아무도 다시는 손대지 않을 글자의 벽이 됩니다. 이미지를 데이터 URI로는 SVG로 판별된 것에는 이 방식을 자동으로 쓰고, ;base64를 고집하는 드문 도구 체인을 위한 체크박스도 있습니다.
SVG에서만 깨지는 따옴표 실수
CSS는 url()을 따옴표 없이 쓰는 것을 허용하고, 평범한 파일 이름이라면 그래도 괜찮습니다.
background-image: url(logo.png);
퍼센트 인코딩한 SVG에 같은 짓을 하면 깨집니다. 따옴표 없는 url() 토큰은 첫 공백이나 괄호, 따옴표, 제어 문자에서 끝나는데 SVG는 속성 사이마다, 경로의 숫자 사이마다 공백으로 가득하고요. 그러면 그 선언이 무효가 되고, CSS는 무효한 선언을 조용히 버립니다. 배경도 오류도 얻지 못하는 것이죠.
인코더가 공백을 이스케이프하지 않아도 되는 이유이기도 합니다. 따옴표로 감싼 URL 안에서 공백은 완벽히 적법하고, 하나하나를 %20으로 바꾸면 파일 속 공백마다 3글자를 더 쓰게 됩니다. 두 결정은 짝입니다. URI에 따옴표를 씌우면 공백은 그대로 두어도 됩니다. 이 도구가 만들어 내는 모든 형태에 따옴표가 씌워져 있는 이유가 정확히 그것입니다.
미디어 타입이 맞아야 합니다
데이터 URI는 자기 타입을 스스로 선언하고, 브라우저는 그 말을 곧이곧대로 믿습니다. 가져온 파일에 대해서는 있는 추측 기반의 대비책이 여기에는 없습니다. 실은 JPEG인 것을 image/png라고 말하면 그림은 그려지지 않고, 쓸모 있는 어디에도 메시지가 남지 않습니다.
이게 중요한 이유는 파일 확장자가 거짓말을 하기 때문입니다. JPEG로 내보낸 뒤 logo.png로 이름이 바뀐 사진은 디스크에서 흔히 볼 수 있는 것입니다. 반면 이미지 파일의 첫 몇 바이트는 그것이 무엇인지를 분명히 말합니다. 모든 형식에 시그니처가 있으니까요. 그러니 도구는 이름이 아니라 파일을 읽어야 합니다. 여기 도구는 그렇게 하고, 둘이 어긋나면 알려 줍니다.
헷갈리는 방식으로 실패하기 때문에 알아 둘 만한 형식이 둘 있습니다. 아이폰이 사진을 찍는 형식인 HEIC와 스캐너가 만들어 내는 TIFF는 둘 다 완벽히 올바른 데이터 URI를 만들지만 Safari를 뺀 어떤 브라우저도 그리지 않습니다. URI가 망가진 것이 아니라 그 형식이 웹이 지원하는 것이 아닐 뿐입니다. 먼저 변환하세요.
공개할 생각이 없었던 메타데이터
데이터 URI는 파일을 바이트 그대로 복사한 것입니다. 디코딩했다가 다시 인코딩하는 일이 없는데, 화질을 잃지 않으니 대개 그게 요점이지요. 다만 파일 안의 그 밖의 모든 것도 함께 온다는 뜻이기도 합니다.
휴대폰에서 막 나온 사진은 EXIF를 싣고 있습니다. 촬영된 자리의 GPS 좌표, 촬영 시각, 카메라 모델, 흔히 그 일련번호까지요. 그것만 파일의 30KB일 수 있습니다. 인라인으로 넣으면 스타일시트 안에서 base64 40KB가 되어 모든 페이지의 임계 경로에 얹힙니다. 그리고 아무도 들여다볼 생각조차 하지 않을 형태로, 저장소에 커밋된 집 주소가 됩니다.
먼저 EXIF 확인 및 제거로 지우세요. 사진을 건드리지 않고 컨테이너만 다시 씁니다. 그에 대한 가이드도 있습니다. 이미지를 데이터 URI로는 JPEG, PNG, WebP에 메타데이터가 얼마나 들었는지 읽어, 무엇을 복사하기 전에 알려 줍니다.
손에 넣은 다음 어디에 둘지
그림이 규칙 하나에만 나온다면 URI를 그 규칙에 두세요. 여러 곳에 나온다면 사용자 지정 속성으로 한 번만 선언하시고요. 아이콘은 호버 상태와 다크 테마까지 세면 대개 여러 곳에 나옵니다.
3KB짜리 URI를 네 규칙에 붙여 넣으면 스타일시트 12KB에, 아이콘이 바뀔 때 고칠 자리가 네 곳입니다. 사용자 지정 속성이라면 각각 하나씩입니다. 테마를 가능하게 해 주는 형태이기도 합니다. 미디어 쿼리 안에서 --icon-search를 다시 정의하면 그것을 쓰는 모든 곳이 따라옵니다.
CSS가 아니라 <img> 태그라면 width와 height를 넣으세요. 인라인된 이미지는 즉시 불려 오므로, 크기가 빠지면 눈에 보이지 않을 만큼 빠르게 일어나는 레이아웃 이동이 되고 그래도 점수는 깎입니다. 예외는 SVG입니다. viewBox만 있는 SVG에는 자기 픽셀 크기가 없는데, 브라우저의 기본값 300×150을 태그에 박아 넣으면 아무도 고르지 않은 크기에 확대 가능한 그림을 못 박는 셈이 됩니다.
alt에 넣을 참된 말이 없다면 비워 두세요. 그 그림이 뜻을 담고 있는지 그냥 장식인지는 넣는 사람만 알고, 파일 이름에서 짐작해 붙인 설명은 화면 낭독기를 쓰는 사람에게 설명이 아예 없는 것보다 나쁩니다.
어디로 가는지가 무엇이 나올지를 정하므로, 복사해 붙여넣는 연습으로 남기지 않고 먼저 묻습니다.
답이 “하지 마세요”일 때
인코딩했을 때 50KB쯤을 넘는 그림이라면 인라인은 틀린 도구이고, 인코딩을 아무리 조심해도 고쳐지지 않습니다. 시도해 볼 만한 순서대로 대안을 적습니다.
작게 만드세요. 인라인으로 넣기에 너무 큰 이미지는 대부분 그냥 너무 큽니다. 이미지 압축이 사진을 말씀하신 용량으로 데려다주고, 이미지 크기 조절이 픽셀 치수를 레이아웃이 실제로 쓰는 만큼으로 깎아 줍니다. 진짜 문제가 그것인 경우가 아주 많거든요.
SVG로 다시 그리세요. 40KB짜리 PNG로 내보낸 아이콘이 900바이트짜리 SVG인 경우가 흔합니다. 압축의 차이가 아니라 형식의 차이이고, 레티나 문제까지 함께 풀어 줍니다.
파일로 두고 preload 하세요.<link rel="preload" as="image">는 바이트를 임계 경로에 올리지 않고 곧바로 가져오기를 시작합니다. 인라인의 이득 대부분을 얻고 캐시의 대가는 치르지 않습니다.
이 중 무엇에도 업로드는 필요 없습니다
파일을 base64로 인코딩하는 것은 산술입니다. 브라우저가 처음부터 갖고 있던 두 함수, btoa와 encodeURIComponent가 하는 일이고요. 그림을 다르게 적어 내겠다고 서버에 갔다 와야 할 기술적 이유는 털끝만큼도 없습니다. 이 일을 하겠다고 파일을 업로드하는 변환기는 사용자를 위해서가 아니라 자기 이유로 업로드하고 있는 것입니다.
여기 도구는 그것을 어디로도 보내지 않습니다. 페이지의 Content-Security-Policy가 연결 가능한 주소를 전부 적어 두는데, 그중 이 사이트의 것은 없습니다. 듣기만 하는 것보다 직접 확인하고 싶다면, 페이지를 불러온 다음 인터넷을 끊고 그냥 인코딩해 보세요. 온라인 변환 사이트에 파일을 올려도 안전할까요?에 어떤 도구에든 해 볼 수 있는 확인 세 가지가 더 있습니다.