Skip to content
ブログに戻る
チュートリアル

画像をBase64とData URIに:画像をインライン化すべき時(2026)

画像をBase64に変換すべき?data URIが有効な場面、33%のサイズ増加、CSS/HTMLへのインライン化、キャッシュのトレードオフ、通常の画像ファイルが勝る場面を解説します。

11 分で読める

画像をBase64に変換すると、得られるのはdata URI、つまり data:image/png;base64,iVBORw0KGgo… のような文字列だ。これはHTMLの src やCSSの url() にそのまま貼り付けられる。ブラウザはその場でデコードし、別途ダウンロードすることなく画像を表示する。ホストするファイルも、追加のリクエストもいらない。

では、そうすべきなのか。指針は短い。小さく(おおよそ2 KB未満)、ほとんど変わらず、HTTPリクエストを1回省きたい画像――小さなアイコンやロゴ――ならBase64としてインライン化する。大きな画像や、複数ページで使い回すもの、ブラウザにキャッシュさせたいものは、通常の画像ファイルのままにしておく。落とし穴は2つある。Base64はファイルを約33%大きくしてしまうし、そのテキストがHTMLやCSSに埋め込まれてしまうと、画像を単独でキャッシュできなくなる。

特定のファイルの正確な数値が知りたければ、Image to Base64 コンバーターがブラウザ内でエンコードを行い、サイズ増加の正確な値を表示してくれる。経験則ではなく実データで判断できるわけだ。本ガイドでは、そのdata URIが実際に何なのか、サイズ税の裏にある計算、インライン化が割に合う場面の判断マトリクス、そして素のファイルが勝つケースを扱う。

「画像をBase64に」で実際に得られるもの:data URI

画像をBase64に変換しても、ファイルが手に入るわけではない。得られるのは、RFC 2397で定義されたdata URI形式に従う1本の長い文字列だ(完全な仕様は MDN の data: URL リファレンス を参照)。この文字列は3つの部分からなる。

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…
└──┬─┘ └───┬───┘ └─┬──┘ └─────────┬──────────┘
data:   MIMEタイプ マーカー  エンコードされた画像バイト列

MIMEタイプは、デコードしようとしているのがどんな種類の画像なのかをブラウザに伝える。画像でよく使われるのは image/pngimage/jpegimage/gifimage/webpimage/svg+xml、そしてfavicon用の image/x-icon だ。;base64, マーカーは、続くペイロードがプレーンテキストではなくBase64であることを示す。カンマ以降のすべてが、印字可能なASCIIとして表現し直された画像そのものだ。

最後の部分はプライバシーの観点で重要になる。変換は FileReader APIの readAsDataURL を通じて完全にブラウザ内で実行され、サーバーには何もアップロードされない。公開前のスクリーンショットや社内図、未発表のアートワークをツールに放り込んでも、ネットワークタブが空のままなのを自分の目で確認できる。生のバイト列がどうやってそのASCII文字列になるのか、その仕組みについてはunderstanding Base64がエンコードを基礎から解説している。complete Base64 guideのほうは、同じdata URLの考え方をフォントやPDF、その他のファイル形式へと広げている。

実例:68バイトの透明PNG

ここに最も実用的な最小ケースを示す――1×1の透明PNG、ディスク上で68バイト、完全なdata URIにすると次のようになる。

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==

これをブラウザのアドレスバーに貼り付けると、有効な画像がネットワーク活動ゼロでレンダリングされる(とはいえ透明なので見えはしないが)。末尾の == はパディングで、これは後ほど触れる。仕組み自体はテキストのBase64とまったく同じで、ただテキストの代わりに画像のバイト列に適用しているにすぎない。プレーンテキストの文字列をエンコードまたはデコードしたいだけなら、Base64 encode/decodeツールがそのケースを扱ってくれる。

33%のサイズ税(そしてそれが累積する理由)

Base64は固定のグループ単位で動く。バイナリ3バイトごとに4つのASCII文字になる。3分の4はおよそ1.33で、ここから+33%という数字が出てくる。小さなファイルでは、1~2バイトのパディングと data:image/png;base64, 接頭辞が加わるぶん、オーバーヘッドがわずかに高くなる。たとえば9 KBのPNGは、約12 KBのテキストになる。

なぜちょうど3対4なのか。Base64は64文字のアルファベット(AZaz09、それに +/)を使う。64個の記号は1文字あたり6ビットの情報だ。一方、バイナリのバイトはそれぞれ8ビット。6と8の最小公倍数は24ビットで、これは3バイト、あるいは4つのBase64文字にあたる。だからエンコーダーは画像を24ビットずつ進んでいく。画像の長さが3のきれいな倍数でないときは、1つか2つの = 文字が最後のグループを埋める。この計算は固定されていて、33%を縮めるエンコーダー設定などは存在しない。

その33%は目に見えるコストだ。隠れたコストは、それが累積することにある。「とにかくインライン化しろ」という助言の多くが飛ばしているのが、この部分だ。

  • 包含するファイルが変わるたびに、画像は再ダウンロードされる。 外部の logo.png はそれ自体が1つのリソースだ。それを styles.css にインライン化すると、色の微調整であれ新しいルールの追加であれ、そのスタイルシートを編集するたびに画像のキャッシュまで無効化されてしまう。訪問者はすでに持っていたはずの画像を、もう一度ダウンロードするはめになる。
  • 単独でキャッシュできない。 通常の画像ファイルは一度取得され、あらゆるページとあらゆる訪問で再利用される。インライン化されたdata URIはドキュメントの一部なので、それを埋め込むすべてのページで、そしてそのドキュメントのキャッシュミスのたびに、再び送られてくる。
  • CSSはレンダリングをブロックする。 ブラウザはCSSを手に入れるまで描画しない。大きなdata URIをスタイルシートに詰め込むと、レンダリングをブロックするリソースがそのぶん大きくなり、ページ全体の初回描画が遅れる。

gzipやbrotliは33%を打ち消すのか?

部分的には打ち消すが、完全にではない。Base64のテキストは十分に反復的なので、gzipやbrotliはこれをよく圧縮し、転送時の膨張のかなりの部分を取り戻す。だが、依然として2つのことが言える。1つ目、圧縮後のBase64は、たいてい圧縮後の元バイナリよりわずかに大きい。圧縮器に効率の悪い出発点を渡しているからだ。2つ目はこちらのほうが大きいのだが、圧縮はキャッシュやレンダリングブロックについては何もしてくれない。転送時に小さくなったdata URIも、ホストファイルとともに再ダウンロードされ、単独ではやはりキャッシュできない。

言い換えれば、圧縮はインライン化のコストを取り除くことと同じではない。minify、gzip、brotliの区別が曖昧なら、code minification guideがそれらの層の積み重なり方を解説している。バイトを絞ったところで、インライン化が生むキャッシュ問題が直るわけではない理由も、そこで分かるはずだ。

Base64画像を使うべき時(判断マトリクス)

判断のすべては、ひと握りの要因に行き着く。それらを並べて示そう。

要因インライン(Base64)寄り通常ファイル寄り
サイズ約2 KB未満(緑)約10 KB超(赤);2~10 KBは判断次第(黄)
再利用1ページ、1~2箇所多くのページで繰り返し使う
変更頻度ほとんど変わらないしばしば編集する
コンテキストHTMLメール、自己完結型ウィジェットやブックマークレット、JSON/APIペイロード、リクエスト1回の節約に値する重要なファーストビューのアイコンコンテンツ画像、共有されるキャッシュ可能なアセット

これらのサイズしきい値は適当に決めたものではなく、Image to Base64 コンバーターに組み込まれた信号機バッジに対応している。2 KB未満は緑、10 KBまでは黄、それ以上は赤だ。ツールが実際のファイルを読み取り、どのバケットに入るかを教えてくれる。

シンプルな経験則

1行だけ覚えるなら、これにしよう。約2 KB未満で1~2箇所でしか使われないなら、インライン化はたいてい割に合う。約10 KBを超えるか複数ページで使い回すなら、通常のキャッシュ可能なファイルがほぼ常に勝つ。2~10 KBの中間が、節約されるリクエストと失われるキャッシュを、自分の具体的な状況に照らして天秤にかける場面だ。

うまく合うケースを詳しく

Base64がきちんと働きを発揮する、いくつかのケースを挙げる。

  • HTMLメール。 多くのメールクライアントは、プライバシーのため外部ホストの画像をデフォルトでブロックする。これでは遠隔のロゴに依存するレイアウトが壊れてしまう。小さくインライン化されたdata URIなら、サーバーフェッチなしで即座にレンダリングされる。ただし対象はロゴとアイコンにとどめ、写真をメールにインライン化してはいけない。
  • 自己完結型のウィジェットとブックマークレット。 ブックマークレットや埋め込み可能なウィジェットは、外部依存ゼロで動く必要がある。アイコンをインライン化すれば、すべてを1つの放り込めるファイルに収められる。
  • JSONとAPIのペイロード。 JSONドキュメントや設定ファイルの中にサムネイルを乗せて送るのが、いちばんすっきりした選択肢になることもある。1往復、1オブジェクトで済み、2回目のリクエストを配線せずにすむ。
  • ファーストビューの重要なアイコン。 小さなロゴがLargest Contentful Paintの一部で、クリティカルパスからリクエストを1回削りたいとき、インライン化は助けになりうる。ここで効くのは、あくまで小さい場合だ。

これらを束ねるパターンは1つしかない。いずれも、アセットが何か別のものといっしょに移動し、そうでなければ独自の配信経路を必要とするケースなのだ。メールはCDNに頼れないし、ブックマークレットには取得すべき2つ目のファイルがなく、JSONレスポンスは単一のペイロードだ。どのケースでも、インライン化しなかった場合の代わりは「キャッシュされたファイル」ではなく「欠落した画像」であり、それが損得勘定をまるごと変えてしまう。だからBase64が合うかどうかの本当のテストは、「小さいか」だけではない。「ここで別ファイルという選択肢がそもそもあるのか」を問うことだ。

インライン化すべきでない時:キャッシュ、遅延読み込み、Core Web Vitals

むしろ反対側のほうが、語ることが多い。インライン化は、ブラウザが本来うまくこなすいくつかのことを、ひっそり無効にしてしまうからだ。

まず、独立したキャッシュを失う。これが再訪問者には最も痛い。通常の画像は初回訪問後にキャッシュへ収まり、以後はずっと即座に読み込まれる。一方、インライン化された画像には独立したキャッシュエントリがなく、毎回ドキュメントに相乗りする。そのためリピーターは、同じバイトコストを訪問のたびに払うことになる。

次に、遅延読み込みを失う。loading="lazy" 属性は、ファーストビューより下にある画像を、ユーザーが近くまでスクロールするまでブラウザに先送りさせる。data URIはHTMLが読まれた瞬間に解析され「ダウンロード」されるので、先送りすべきものがそもそも残らない。ファーストビュー外の画像を12枚インライン化すれば、その12枚を全部、初回読み込みに押し込んだことになる。

そして、レンダリングをブロックするリソースが肥大化する。先述のとおり、CSS内のdata URIは初回描画をブロックするリソースを膨らませる。そのスタイルシートが大きいほど、ページは長く空白のまま居座る。

モバイルではデコードのコストが高い。 data URIはドキュメントを読み込むたびにBase64のデコードが必要で、低スペックの端末ではこのCPU処理が積み重なる。しかもそのバイト列はブラウザのディスクキャッシュに入らないため、重いインライン画像は訪問のたびに再デコードされる。通常のファイルなら一度キャッシュしてデコードすれば済む話だ。

この助言が変化してきたのには歴史的な事情もある。インライン化の本来の論拠は、HTTP/1.1時代に声高に主張されたリクエスト削減だった。各接続は一度に1つのリソースしか取得できなかったので、40個の小さなアイコンを持つページは40往復を払っていた。HTTP/2は多くのリクエストを単一接続で多重化することでこれを変え、余分な小さいファイルのコストを下げた。こうしてインライン化の大きな見返りであるリクエスト削減はほぼ蒸発し、失われるキャッシュ、効かない遅延読み込み、大きくなるレンダリングブロックファイルといったコストだけが残った。Base64スプライトに熱を上げる古い記事を読むなら、自分のサイトが今日実際に走らせているプロトコルに照らして判断してほしい。

Core Web Vitalsの観点

インライン化はLCP(Largest Contentful Paint)に対して両刃の剣だ。LCP要素そのものである小さなファーストビューの画像なら、リクエストを取り除くことでLCPをわずかに早めうる。だが大きな画像をインライン化すると逆のことが起きる。それが収まるドキュメントやスタイルシートを遅らせ、ページ全体のLCPを後ろにずらしてしまう。どちらに転ぶかは、サイズのしきい値が決める。

CLS(Cumulative Layout Shift)については、インライン化はコアのルールを何も変えない。画像にはやはり明示的な widthheight(またはaspect-ratioボックス)が必要で、それがあればブラウザはレンダリング前に領域を確保できる。寸法のないdata URIは、寸法のない遠隔画像とまったく同じようにレイアウトをずらす。

インライン化よりも良いレバーは、たいてい元画像を縮めることだ。エンコード前に画像を圧縮しておけば、ファイルも、そこから得られるdata URIも、両方小さくなる。クライアント側やビルドステップでそれを行う方法はbrowser vs Node image compression guideが扱っている。そもそも小さく済む形式の選び方ならWebP vs AVIF vs JPEGが参考になる。

HTML、CSS、Markdown、JSONで画像をインライン化する方法

data URIを手に入れたら、あとは各コンテキストに落とし込むだけだ。次の4つは、Image to Base64 コンバーターが生成してくれる、貼り付けてすぐ使えるスニペットでもある。

HTML ――URIを任意の src に貼り付ける。

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…" alt="logo">

CSS ――background-image のために url() で包む(これが正統なCSSでのbase64画像パターンだ)。

.icon {
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0i…");
}

Markdown ――ファイルをホストできないREADME、GitHubのissue、ノートブック向けの自己完結型画像リンク。

![chart](data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ…)

JSON ――APIや設定ペイロードの中に埋め込むアセット。

{ "icon": "data:image/png;base64,iVBORw0KGgo…" }

4つすべてが、URLを受け付けるあらゆる場所で機能する。img src、CSSの backgroundmask-image、faviconの <link> でさえも。現代のブラウザはどれも data: スキームをサポートしている。

これらを素早く生成する

これらを手作業で組み立てるのは間違いやすい。MIMEタイプが1つ違ったり改行が紛れ込んだりすると、画像は黙ってレンダリングに失敗する。ファイルをImage to Base64 コンバーターに放り込めば、それぞれにコピーボタンの付いた4つのスニペットが生成される。サイズ増加の正確な値も出るので、そのアセットがそもそもインラインに向くのかどうかを先に把握できる。

SVG:Base64がたいてい負ける特例

SVGは通常の論理を破る。SVGはバイナリではなくテキストだからだ。Base64はバイナリデータをテキスト安全にするために存在するが、SVGはすでにXMLのテキストになっている。それをBase64としてエンコードしても、エンコードの必要がなかった文字列を膨らませ、おまけに読めなくするだけだ。だからSVGに限っては、Base64はほぼ常に間違った選択になる。

同じアイコンをインライン化する3つの方法を比べてみよう。

/* 1. Base64 data URI — 必要のなかったテキストに33%の税を加える */
.a { background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0i…"); }

/* 2. URL エンコードした data URI — 一握りの文字をパーセントエンコード、33%の税なし */
.b { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'…%3C/svg%3E"); }

/* 3. HTML に直接 <svg> をインライン — CSS で完全にスタイル可能 */
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
  <path d="M12 2 L22 22 H2 Z" fill="currentColor" />
</svg>

選択肢2(URLエンコード)は通常、選択肢1より小さくて済み、人間が読める状態を保ったまま、より良く圧縮される。URIを壊しかねない文字(<>#、引用符)だけをパーセントエンコードし、残りは読めるままにしておくからだ。URL encoder/decoderのアプローチはツール自体に説明がある。Base64 SVGに手を伸ばすのは、ビルドパイプラインがそれを特に要求するときだけにしよう。

インライン <svg> がBase64 PNGアイコンにしばしば勝る理由

Base64エンコードされたPNGアイコンとインライン <svg> のどちらかを選ぶなら、たいていの面でSVGが勝つ。ぼやけることなくどんなサイズにもスケールし、33%の税を負わず、しかもどんなdata URIとも違って、CSSでスタイルを当てたりアニメーションさせたり、currentColor で色を変えたりできる。Base64 PNGのほうは、いったんエンコードしたら手を入れられない固定解像度のかたまりだ。ラスターのBase64は、写真やラスターのスクリーンショットをどうしてもインラインで必要とするケースのために取っておこう。

逆方向のデコード:Base64から画像へ

逆の問題も同じくらいよくある。APIレスポンスやログ行、データベースのカラム、デバッグ中のスタイルシートから抜き出したBase64文字列を手にしていて、実際の画像を見たい、という状況だ。

ここで人がつまずく細かい点が2つある。1つ目は、生のBase64と完全なdata URIの違いだ。完全なdata URI(data:image/png;base64,…)は自身のMIMEタイプを携えているが、むき出しのペイロード(iVBORw0KGgo…)は携えていない。むき出しのペイロードをレンダリングするには、正しい data: 接頭辞を前置するか、先頭バイトから形式をツールに推測させるかだ。iVBORw0KGgo ならPNG、/9j/ ならJPEG、R0lGOD ならGIFを意味する。

2つ目は、行の折り返しだ。メールや古いツールから来たBase64は、RFC 2045に従って76文字ごとに折り返されていることが多い。その改行はデコード前に取り除かなければならない。そうしないと、文字列はHTML属性や url() の中で無効になってしまう。

ブラウザでは、完全なdata URIをそのまま <img> に渡せる。

<img src="data:image/png;base64,iVBORw0KGgo…" alt="decoded">

サーバー側では、Nodeがペイロードからファイルを再構築する。

import { writeFileSync } from "node:fs";

const b64 = "iVBORw0KGgoAAAANSUhEUgAA…"; // raw payload, no data: prefix
writeFileSync("output.png", Buffer.from(b64, "base64"));

コードを書かずに済ませたいなら、Base64 to Image コンバーターを使おう。文字列を貼り付ければ(接頭辞のあり/なし、改行込みでも構わない)プレビューが出て、寸法とMIMEタイプが読み取れ、本物のPNGやJPG、GIF、SVGをダウンロードできる。空白は取り除かれ、接頭辞の欠落は許容され、形式はマジックバイトから自動検出される。

デコードした画像には、やっておく価値のある健全性チェックが1つある。報告された寸法を見ることだ。複数の文字列を保持していたファイルから1つ抜き出して、結果が1×1なら、欲しかったアセットではなくトラッキングピクセルをつかんでしまった可能性が高い。それから、デコードが純粋に機械的で可逆だという点も覚えておこう。Base64 PNGは、まったく同じPNGとして、1バイトも違わず、再圧縮もなく戻ってくる。その過程で変わるのはコンテナだけだ。出ていくときはテキスト文字列、戻ってくるときはバイナリファイル、というわけだ。

FAQ

画像をBase64に変換すべき?

それに値するときだけだ。小さく(約2 KB未満)、ほとんど変わらず、HTTPリクエストを1回省くことが重要なアイコンやロゴ、加えてHTMLメール、自己完結型ウィジェット、JSONペイロードのときだ。大きな画像や複数ページで使い回すものは、ほぼ常に通常のファイルのままにすべきで、そうすればキャッシュと遅延読み込みを保てる。

Base64は画像をどれだけ大きくする?

約+33%だ。Base64はバイナリ3バイトごとを4つのASCII文字としてエンコードし、そこに少しのパディングと data: 接頭辞がつく。9 KBのPNGはおよそ12 KBのテキストになる。手元のファイルの正確な増加が知りたければ、画像をBase64に変換すればツールがメタデータバーに数値を出してくれる。

Base64は画像の読み込みを速くする?

ごく小さなファーストビューのアイコンなら、リクエスト1往復を省けるので速くなりうる。より大きな画像や使い回す画像では、たいてい遅くなる。独立したキャッシュを失い、遅延読み込みできず、CSSへのインライン化はレンダリングをブロックするリソースを大きくする。サイズが決め手だ。

CSSでBase64画像を使える?

使える。background-image: url("data:image/png;base64,…")。ごく小さなアイコンには問題ない。ただし、そのdata URIはスタイルシートの一部になるので、CSSが変わるたびにファイル全体が再ダウンロードされ、画像をそれと別にキャッシュできないことは覚えておこう。

アイコンにはSVGとBase64のどちらを使うべき?

インライン <svg> かURLエンコードしたSVG data URIを優先しよう。SVGはテキストで、きれいにスケールし、33%の税を負わないので、たいていBase64 PNGより小さく、CSSでスタイルもできる。Base64に手を伸ばすのは、ラスターアイコンが特に必要なときだけにしよう。

Base64文字列を画像に戻すには?

ブラウザでは、完全な data:image/…;base64,… のURIを <img src> に放り込む。サーバーでは、Buffer.from(b64, "base64") を使ってファイルを書き出す。生のペイロードには data: 接頭辞の追加が必要で、行折り返しされた文字列はまず改行を取り除く必要がある。Base64 to Image ツールはそのすべてを扱い、結果をダウンロードさせてくれる。

タグ: base64 data-uri images performance css web-performance