# 画像をCSSの中に入れるべきとき、そうでないとき

スタイルシートに書き込まれた画像は、それと一緒に届きます。2度目のリクエストも、待ち時間もありません。その代わり、それはファイルであることをやめます。単独ではキャッシュされず、周りの何かが変わるたびに再ダウンロードされます。ここでは、その取引が割に合う場所と、静かに割に合わなくなる場所を説明します。

[画像→データURI変換ツールを開く](https://abox.tools/ja/image-to-data-uri/): 画像まるごとを1行のテキストに。そのままCSSやHTMLに貼れます。

最終更新 2026年8月26日

## 短い答え

[画像をデータURIに](https://abox.tools/ja/image-to-data-uri/)を開いて画像を入れ、*CSSカスタムプロパティ*を選び、その行をスタイルシートの先頭に貼ります。あとは必要なところで`background-image: var(--logo)`として使ってください。

そうするのは、画像が小さく、しかもどのページでも必要な場合です。アイコン、箇条書きの点、山形記号、模様といったものです。写真ではやらないでください。以下は、この2文がなぜ違うのか、そして自分がどちらを見ているのかを見分ける方法です。

## データURIとは実際何なのか

あるものを指すのではなく、そのものを含んでいるアドレスです。スタイルシートは、ふつうこう書きます。

```
background-image: url("logo.png");
```

そしてブラウザは`logo.png`を取りに行きます。データURIは、こう書きます。

```
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...");
```

そして、取りに行くものはありません。画像はすでにそこに、文字として書き出されています。部分は3つです。`data:`がスキーム。`image/png`がメディアタイプで、ブラウザはこれを完全に信じます。それについては後述します。カンマから後ろがファイルです。

考え方は、これで全部です。小手先の技でも裏技でもありません。1998年から標準にあり、それ以降に出たすべてのブラウザで動きます。

## 得られるもの。往復が1回減る

節約されるのは帯域ではありません。リクエストです。

ブラウザは、`logo.png`に言及しているスタイルシートを読むまでは、それを要求できません。そしてそのスタイルシートを取ってくるまでは、読めません。ですからふつうの背景画像は、ページ読み込みの中で少なくとも往復2回分の深さにあります。そして遅い回線のスマホでは、ファイルがどれだけ小さかろうと、1回の往復が数百ミリ秒になりえます。600バイトの山形記号は、転送にほとんど費用がかからないのに、届くまでに4分の1秒かかることがあるのです。

埋め込めば、スタイルシートと一緒に届きます。利点はそれで全部ですし、画面の上部に現れる小さなアイコンにとっては、それは本物の利点です。

## 代償。3分の1、そしてキャッシュ

**base64は3分の1ほどを足します。**ファイルの3バイトが4文字になります。URLが許す文字だけで任意のバイト列を書くには、それだけかかるからです。それを避ける賢いエンコーダーは存在しません。9KBのPNGは、12KBのスタイルシートです。

**圧縮は、それを返してくれません。**ここが、人が勝手に大丈夫だと思っている部分です。GzipやBrotliは冗長性を見つけることで働きますが、PNGもJPEGもWebPも、すでに圧縮されています。残っている冗長性はごくわずかですし、base64は何も足しません。実際に取り戻せるのは、その3分の1のさらに10分の1程度で、全部ではありません。（SVGは逆の場合で、次の節がそれについてです。）

**ファイルであることをやめます。**これは、たいていの測定には現れない代償であり、大きさが効いてくると問題になるほうです。

- **単独ではキャッシュされません。**ふつうの画像は一度取得され、1年間再利用されます。埋め込まれた画像はスタイルシートの一部なので、スタイルシートのキャッシュ項目と運命をともにします。
- **何かを変えると、すべてが再ダウンロードされます。**余白をひとつ直して新しいスタイルシートを配れば、訪問者は全員、埋め込まれた画像も一緒にもう一度ダウンロードします。2年間変わっていない画像をです。
- **クリティカルパスの上に乗ります。**スタイルシートは描画を止めます。画像は止めません。画像を埋め込むことは、それを後者から前者へ移すことです。画像を含む全体が届くまで、ページは描画できません。
- **並行して取得されません。**ブラウザは多くのものを同時にダウンロードします。埋め込まれた画像は独立したものではないので、その恩恵をまったく受けません。

おおよその目安です。ブラウザの挙動が変わる境目ではなく、助言が変わる境目だと思ってください。2KB程度までなら明らかに得。10KB程度までなら、どのページにも出るものについてはたいてい見合います。50KBを超えると、エラーメッセージの出ない間違いです。[この道具](https://abox.tools/ja/image-to-data-uri/)は、各結果がどの帯に落ちるのかを、文字数とともに表示します。

![出力のカード。base64のデータURIを含むCSSの規則と、その横に元ファイルの大きさとエンコード後の大きさ。](https://abox.tools/screens/embed-an-image-in-css/output.webp)

エンコードした写しは、元のファイルより三割ほど大きくなります。この節が扱う代償はこれで、見つけさせるのではなく書き出してあります。

## 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/ja/image-to-data-uri/)は、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`にしていたら、ファイル中の空白1つにつき3文字かかります。この2つの判断は、対になっています。URIを引用符で囲めば、空白はそのままにできます。この道具が出すどの形も引用符で囲まれているのは、まさにこの理由です。

## メディアタイプは正しくなければなりません

データURIは自分の種類を宣言し、ブラウザはその言葉をそのまま受け取ります。取得したファイルに対して行われるような、中身を見て推測する代替手段はありません。実際はJPEGのものについて`image/png`と言えば、画像は表示されませんし、役に立つ場所にメッセージも出ません。

これが効いてくるのは、拡張子が嘘をつくからです。JPEGとして書き出された写真が`logo.png`という名前になっているのは、ディスクの上でふつうに見つかるものです。一方、画像ファイルの先頭数バイトは、それが何であるかを曖昧さなく述べています。どの形式にも署名があるからです。ですから道具は、名前ではなくファイルを読むべきです。ここの道具はそうしますし、両者が食い違うときには知らせます。

混乱を招く形で失敗するので、知っておく価値のある形式が2つあります。iPhoneが写真を撮る形式である**HEIC**と、スキャナーが作る**TIFF**です。どちらも完全に正しいデータURIになりますが、Safari以外のブラウザは、それを描きません。URIが壊れているのではなく、その形式がウェブの対応するものではないだけです。先に変換してください。

## 公開するつもりのなかったメタデータ

データURIは、ファイルの1バイトずつの複製です。デコードも書き直しも行われませんし、たいていそれこそが目的です。画質が失われないからです。ですが同時に、ファイルの中のそれ以外もすべて付いてくる、ということでもあります。

スマホから出したばかりの写真は、EXIFを抱えています。撮影地のGPS座標、撮影日時、カメラの機種、そしてしばしばそのシリアル番号です。それがファイルの30KBになることもあります。埋め込めば、スタイルシートの中の40KBのbase64となり、すべてのページのクリティカルパスに乗ります。そして自宅の住所が、誰も見ようと思わない形でリポジトリにコミットされます。

先に[EXIFビューアー・削除ツール](https://abox.tools/ja/exif-editor/)で外してください。画像に触れずに、入れ物だけを書き直します。[そのガイド](https://abox.tools/ja/guides/remove-exif-and-gps-data/)もあります。画像をデータURIにする道具は、JPEG・PNG・WebPにどれだけメタデータがあるのかを読み取り、何かをコピーする前にそれを伝えます。

## 手に入れたら、どこに置くか

画像が1つのルールにしか出てこないなら、URIをそのルールに置いてください。2つ以上に出てくるなら、カスタムプロパティとして一度だけ宣言してください。アイコンはたいてい2つ以上に出てきます。ホバー時の状態とダークテーマを数えれば、なおさらです。

```
: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を4つのルールに貼れば、12KBのスタイルシートと、アイコンを変えるときに直す4か所になります。カスタムプロパティなら、どちらも1つです。テーマ切り替えが成り立つ形でもあります。メディアクエリの中で`--icon-search`を定義し直せば、それを使っているすべてが従います。

CSSではなく`<img>`タグに入れる場合は、`width`と`height`を書いてください。埋め込まれた画像は即座に読み込まれるので、サイズがないと、見えないほど速く起きるレイアウトのずれが発生しますし、それでも減点はされます。例外はSVGです。`viewBox`しか持たないSVGには固有のピクセルサイズがないので、ブラウザの既定である300×150をタグに書き込むと、拡大縮小できる画像を、誰も選んでいない大きさに固定してしまいます。

`alt`は、そこに書くべき本当のことがない限り、空にしておいてください。その画像が意味を運んでいるのか、飾りなのかを知っているのは書く人だけですし、ファイル名から推測した説明は、スクリーンリーダーを使う人にとって、説明がまったくないより悪いからです。

![形のカード。出力を選ぶボタンが並び、CSSの背景規則、imgタグ、URIそのもの、そしてbase64か素のSVGかのスイッチがあります。](https://abox.tools/screens/embed-an-image-in-css/shape.webp)

どこへ持っていくかで出力が決まるので、コピー＆ペーストの練習に任せず先に尋ねます。

## 答えが「やめておけ」のとき

エンコード後に50KBを超えるなら、埋め込みは間違った道具であり、エンコードをどれだけ丁寧にやっても直りません。試す価値のある順に、代わりの手を挙げます。

- **小さくします。**埋め込むには大きすぎる画像は、たいてい全般的に大きすぎます。[画像圧縮ツール](https://abox.tools/ja/compress-image/)は写真を指定したサイズまで持っていきますし、[画像リサイズツール](https://abox.tools/ja/resize-image/)はピクセル寸法を、レイアウトが実際に使う分まで落とします。本当の問題は、非常にしばしばそちらです。
- **SVGとして描き直す。**40KBのPNGとして書き出されたアイコンは、しばしば900バイトのSVGです。これは圧縮の差ではなく形式の差ですし、高精細画面の問題も同時に解決します。
- **ファイルのまま残して、先読みさせる。**`<link rel="preload" as="image">`は、バイト列をクリティカルパスに移さずに、取得をすぐ始めます。埋め込みの利点の大半が得られ、キャッシュの代償はまったくありません。

## これにアップロードは要りません

ファイルをbase64にエンコードするのは、計算です。ブラウザが最初から持っている2つの関数、`btoa`と`encodeURIComponent`であり、書き方を変えるために画像がサーバーまで往復しなければならない技術的な理由は、一切ありません。これをするためにファイルをアップロードさせる変換サイトは、こちらの理由ではなく、自分の理由でアップロードしています。

[ここの道具](https://abox.tools/ja/image-to-data-uri/)は、どこへも送りません。ページの`Content-Security-Policy`には接続してよいアドレスがすべて挙がっていますが、そのどれも当サイトのものではありません。言われるより確かめたい方は、ページを読み込んでから回線を抜き、それでもエンコードしてみてください。[オンライン変換サイトにファイルをアップロードしても安全ですか？](https://abox.tools/ja/guides/is-it-safe-to-upload-files/)には、どの道具にも試せる確認方法がさらに3つ載っています。
