Base64とは何か
Base64は、バイナリデータを64種類の印刷可能なASCII文字で表現するバイナリ→テキスト変換エンコーディング方式です。使用される文字は、大文字A–Z、小文字a–z、数字0–9、そして記号+と/です。入力のバイト数が3の倍数でない場合は、末尾に=のパディング文字が付加されます。
「Base64」という名前は、この文字セットのサイズから直接来ています。セット内の各文字は正確に6ビットで表現できるため(2⁶ = 64)、Base64は3バイト(24ビット)のバイナリデータを4つの印刷可能な文字(4 × 6ビット = 24ビット)にエンコードします。これにより、完全に可逆なロスレスエンコーディングが実現されます。
Base64は元々、テキストデータしか確実に送信できなかった電子メールシステム(MIME)のために設計されました。今日では、バイナリデータがテキストのみのチャンネルを通る必要がある場面——メール添付ファイル、JSONペイロード、HTMLのData URI、JWTトークンなど——で広く利用されています。
なぜ画像をBase64にエンコードするのか
主な動機は、バイナリの画像データをテキスト文書に直接埋め込むことです。PNGやJPEGファイルは生のバイナリデータであり、HTMLファイルやJSONオブジェクトにそのまま貼り付けることはできません。Base64はプレーンテキスト文字列を生成することでこの問題を解決し、テキストが使える場所ならどこにでも安全に配置できるようにします。
開発者がBase64画像エンコードを選ぶ主な理由
- HTTPリクエストの削減 — 画像のインライン化により、ネットワークリクエストが1回完全に排除されます。小さなアイコンや装飾的な要素では、クリティカルレンダリングパスの時間を大幅に短縮できます。
- 単一ファイルの配布 — 自己完結型HTMLファイル(レポート、メールテンプレート、オフラインデモ)が外部依存なしにすべてのアセットを保持できます。
- HTMLメールの互換性 — 多くのメールクライアントはプライバシー上の理由から外部画像の読み込みをデフォルトでブロックします。インラインBase64画像はこの制限を回避できます。
- APIペイロード — JSONボディの一部として画像を送信する場合(例:ユーザーアバターのアップロードエンドポイント)、Base64でファイルを文字列フィールドにエンコードできます。
- CSSの背景 — スタイルシートに小さなData URIを埋め込むことで、装飾的なスプライトやアイコン用の追加リクエストを回避できます。
- コンテンツセキュリティポリシー(CSP) — インライン画像はCSPの
img-srcホスト制限の対象外であり、制約のある環境でのポリシー設定を簡素化できます。
Base64エンコードの仕組み
アルゴリズムのステップバイステップ解説
Base64は3バイト単位(一度に24ビット)で入力を処理します。
- 次の3バイトを取得:
B1 B2 B3 - それらのビットを連結して24ビット文字列を作成
- 24ビットを4つの6ビットグループに分割
- 各6ビット値(0–63)を検索テーブルを使ってBase64文字にマッピング
- すべてのバイトが処理されるまで繰り返す
- 最後のチャンクが3バイト未満の場合は
=文字でパディング
具体例
ASCII文字列Man(バイト0x4D 0x61 0x6E)のエンコード:
M a n
01001101 01100001 01101110 ← 24ビット
010011 010110 000101 101110
19 22 5 46
T W F u
結果:TWFu — 3バイトが4文字になりました。
約33%のサイズ増加の理由
4つのBase64文字はそれぞれ6ビットの情報を持ち、合計24ビットです。同じ24ビットが元々3バイト(24ビット)に収まっていました。表現形式が大きくなる理由は、各出力文字が6ビットではなく完全な8ビットのASCIIバイトとして格納されるからです。
- 入力:3バイト = 3 × 8 = 24ビットのストレージ
- 出力:4文字 = 4 × 8 = 32ビットのストレージ
- オーバーヘッド:32 / 24 = 1.333… → 約33.3%増加
gzip/Brotli圧縮を適用すると、Base64エンコードされたテキストは非常によく圧縮されます(元のサイズに近づく)。これにより、HTTPレスポンスでのオーバーヘッドが部分的に軽減されます。
Data URIの詳細
Data URI(Data URLとも呼ばれる)は、RFC 2397で定義されたフォーマットを使って、ファイルの内容をURI文字列に直接埋め込みます。
data:[<mediatype>][;base64],<data>
| 部分 | 説明 |
|---|---|
data: |
スキーム識別子 |
<mediatype> |
MIMEタイプ(例:image/png、image/svg+xml) |
;base64 |
データがBase64エンコードされていることを示す(プレーンテキストの場合は省略) |
,<data> |
エンコードされた(またはプレーンな)データペイロード |
例
<img>タグにPNG画像を埋め込む:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..." alt="アイコン">
CSSにSVG背景を設定:
.logo {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...");
}
Base64を使わないSVG(URLエンコード):
SVGはすでにテキストなので、パーセントエンコーディングを使ってBase64なしで埋め込めます:
.icon {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'...%3E%3C/svg%3E");
}
SVGにURLエンコードを使うと、同じ画像に対してBase64より小さな出力が得られます。
実用的なコード例
ブラウザ:FileReader API
// ブラウザで画像ファイルをBase64に変換する
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
});
}
// 使用例
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
const base64 = await fileToBase64(e.target.files[0]);
document.querySelector('img').src = base64;
});
reader.resultにはすでに完全なData URIプレフィックス(例:data:image/png;base64,...)が含まれているため、そのままsrcに代入できます。
ブラウザ:Canvas API(リサイズ+エンコード)
function resizeAndEncode(file, maxWidth = 200) {
return new Promise((resolve) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
const scale = Math.min(1, maxWidth / img.width);
const canvas = document.createElement('canvas');
canvas.width = img.width * scale;
canvas.height = img.height * scale;
canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
URL.revokeObjectURL(url);
resolve(canvas.toDataURL('image/webp', 0.85));
};
img.src = url;
});
}
JavaScript:Base64をバイナリにデコード
// Base64 Data URIをBlobにデコード
function dataURItoBlob(dataURI) {
const [header, data] = dataURI.split(',');
const mime = header.match(/:(.*?);/)[1];
const binary = atob(data);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return new Blob([bytes], { type: mime });
}
Python:エンコードとデコード
import base64
# 画像をBase64にエンコード
with open("image.png", "rb") as f:
encoded = base64.b64encode(f.read()).decode("utf-8")
data_uri = f"data:image/png;base64,{encoded}"
print(data_uri[:80], "...") # プレビュー
# Base64を画像にデコード
image_data = base64.b64decode(encoded)
with open("output.png", "wb") as f:
f.write(image_data)
CSS:小さなアイコンを埋め込む
/* CSSに小さなアイコンを埋め込む */
.icon {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...");
width: 24px;
height: 24px;
}
/* 小さなSVGはURLエンコードの方が読みやすい */
.icon-alt {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E...%3C/svg%3E");
}
実際のユースケース
1. メールテンプレート
Outlook、Gmail(一部の状況)、企業向けWebメールなどのメールクライアントは、プライバシーの理由からデフォルトで外部画像の読み込みをブロックすることが多いです。小さな画像をHTML内にBase64 Data URIとして埋め込むことで、クライアントのプライバシー設定に関わらず常に表示されることが保証されます。
2. プログレッシブWebアプリ(PWA)とオフラインファーストアプリ
重要な画像をHTMLシェルやService Workerキャッシュアセットにインライン化することで、追加のキャッシュエントリなしにデバイスがオフラインでも利用可能になります。
3. Canvasベースの画像処理パイプライン
canvas.toDataURL()は、ブラウザ内での画像変換(リサイズ、透かし追加、フォーマット変換)の標準的な出力メカニズムで、サーバーへのアップロード前に使用されます。
4. データエクスポート機能
外部ホスティングなしに画像を含む必要があるダウンロード可能なレポート(PDF、ZIP、HTML)の生成。完全自己完結型のHTML請求書をメールで送ったりアーカイブしたりする場合、画像リンクの切れを心配する必要がありません。
5. CSSスプライトの代替
一度限りの小さなアイコンには、単一のBase64エンコードされたSVG背景画像の方がスプライトシートを管理するより簡単なことがあります。
比較:Base64埋め込み vs 外部ファイルホスティング
| 要素 | Base64埋め込み | 外部ファイル |
|---|---|---|
| HTTPリクエスト数 | 0(インライン済み) | 画像ごとに1回 |
| ファイルサイズオーバーヘッド | 約33%増加 | なし |
| ブラウザキャッシュ | 個別にキャッシュされない | URLでキャッシュ |
| CDN配信 | 非対応 | フルCDNサポート |
| キャッシュ無効化 | 親文書を更新 | ファイル名/ハッシュを変更 |
| 最適な用途 | 小さなアイコン(5KB未満) | 写真、大きな画像 |
| メール互換性 | 優秀 | しばしばブロックされる |
| オフラインサポート | 組み込み済み | Service Workerが必要 |
パフォーマンスのトレードオフと考慮事項
Base64がパフォーマンス向上に役立つ場合
- 非常に小さな画像(2–5KB未満): 小さなファイルのHTTPリクエストコスト(DNSルックアップ + TCPハンドシェイク + TLSネゴシエーション + リクエスト/レスポンス)が33%のサイズペナルティを上回ることが多い。
- HTTP/1.1環境: ブラウザはホストごとの並列接続数を制限している(通常6本)。ここではリクエスト数の削減がHTTP/2より大きな効果を持つ。
- ファーストビューの重要な画像: ロゴやヒーローアイコンをインライン化すると、最初のHTMLバイトと共にレンダリングされる——追加の往復通信が不要。
Base64がパフォーマンスを低下させる場合
- 大きな画像(5–10KB超): サイズオーバーヘッドが顕著になる。100KBのPNGがBase64では約133KBになる。
- 繰り返し使用する画像: 外部画像ファイルは一度ダウンロードされ、複数ページにわたってキャッシュから再利用される。各ページに埋め込まれたBase64文字列は毎回のページ読み込みで再ダウンロードされる。
- HTTP/2の多重化: HTTP/2では多数の小さなリクエストが単一の接続で多重化され、オーバーヘッドはほぼゼロ。「リクエストを減らす」という論拠は大幅に弱まる。
- ドキュメントの解析時間: 大きなインラインBase64文字列はHTMLの解析時間とDOMのシリアライズコストを増加させる。
- ブラウザキャッシュ: HTMLに埋め込まれたData URIはドキュメントの一部としてのみキャッシュされる。独立したキャッシュエントリを持たないため、ページをまたいで共有できない。
圧縮についての注記
Base64エンコードされたテキストは、限られた文字セットや繰り返しパターンによる高い冗長性のため、gzip/Brotliで非常によく圧縮されます。HTTP圧縮が有効な場合、典型的な画像の実効転送サイズの増加は約2–8%程度に抑えられ、損益分岐点が大幅に改善されます。
ベストプラクティス
サイズのしきい値を設ける。 2–5KB以下の画像はインライン化し、それより大きいものは外部URLを使用する。多くのバンドラー(webpack、Vite)が
url-loader/asset/inlineでこのルールを自動的に適用する。アイコンにはSVGを優先。 SVGはすでにテキストであり、ラスター形式のBase64よりも圧縮効率が高く、CSSでスタイリングも可能。SVGには(Base64ではなく)
encodeURIComponentによるURLエンコードを使い、可読性を保つ。HTTP圧縮を有効にする。 サーバーでgzipまたはBrotli圧縮を確実に有効化することで、33%のオーバーヘッドが転送時にほぼ解消される。
WebPまたはAVIFを使用する。 現代的なフォーマットはエンコード前に大幅に小さなファイルを生成するため、Base64出力も比例して小さくなる。
DevToolsで確認する。 Networkパネルをチェック。インライン画像がHTMLドキュメントを著しく大きくしている場合は、適切なCDNと長期キャッシュヘッダーを持つ外部URLへの移行を検討する。
メールはクライアントをまたいでテストする。 すべてのメールクライアントがData URIを同じようにレンダリングするわけではない。重要なメールコンテンツにインライン画像を使う前に、Outlook、Gmail(WebとApp)、Apple Mail、モバイルクライアントでテストする。
エンコード前にメタデータを除去する。 埋め込む前にEXIFデータを除去するツールを使う——EXIFは不要なデータをキロバイト単位で追加する可能性があり(GPSの位置情報などの機密データを含む場合も)、問題になることがある。
ビルド時のツールを使う。 画像を手動でエンコードするのではなく、webpackの
asset/inline、Viteの?inlineインポートサフィックス、またはPostCSSのpostcss-inline-base64を使ってプロセスを自動化する。
SVG vs ラスター画像:エンコードの注記
SVG画像はXMLテキストなので、マークアップをURLエンコードするだけでBase64なしにCSSに埋め込むことができます。このアプローチが推奨される理由:
- SVGコンテンツに対してBase64よりも小さな結果が得られる。
- スタイルシート内でSVGが人間にとって読みやすい状態を保てる。
- デコードのオーバーヘッドがない。
/* URLエンコードされたSVG — SVGにはこちらが推奨 */
.checkmark {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E");
}
/* Base64エンコードされたSVG — 許容されるが可読性が低い */
.checkmark-b64 {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTkgMTYuMTdMNC44MyAxMmwtMS40MiAxLjQxTDkgMTkgMjEgN2wtMS40MS0xLjQxeiIvPjwvc3ZnPg==");
}
よくある質問(FAQ)
Q1:Data URIの最大サイズはどのくらいですか?
明確な標準的上限はありませんが、ブラウザには実際的な制限があります。ChromeとFirefoxは最大約2MBのData URIを問題なく処理します。Internet ExplorerはData URIを32KBに制限していました。本番環境では、ドキュメントの解析時間への影響を避けるために埋め込み画像を5KB未満に保つことをお勧めします。
Q2:CSSのcontent:プロパティにBase64画像を使えますか?
はい。擬似要素はcontent: url(...)内でData URIを受け入れます:
.badge::before {
content: url("data:image/png;base64,...");
}
content: url()は画像を固有のサイズでレンダリングし、width/heightでサイズ調整できないことに注意してください。サイズ制御が必要な場合はbackground-imageを使用してください。
Q3:Base64エンコードは画像品質に影響しますか?
いいえ。Base64はロスレスエンコーディングです。元のバイトをまったく変更することなく、完全に同じ内容でエンコード・デコードします。画像品質は元の画像ファイルとそのフォーマット(非可逆JPEGか、可逆PNG/WebPか)によってのみ決まります。
Q4:Base64文字列をファイルにデコードするには?
ブラウザの場合:
const byteString = atob(base64String); // デコード
Pythonの場合:
import base64
data = base64.b64decode(b64_string)
Node.jsの場合:
const buf = Buffer.from(b64String, 'base64');
Q5:Base64エンコードされた画像は検索エンジンにインデックスされますか?
検索エンジンはData URI経由で配信された画像をインデックスできますが、外部ホスティングされた画像ほど効率的にクロールされない可能性があります。SEOが重要な画像には、説明的なファイル名、適切なalt属性、構造化データマークアップを使用して外部ホスティングすることをお勧めします。
Q6:Base64文字列の末尾が==で終わるのはなぜですか?
パディング文字(=)は入力バイト数が3で割り切れない場合に追加されます。=が1つの場合、最後のチャンクは2バイト(16ビット → 18ビットにエンコード → パディング1文字)。==が2つの場合、最後のチャンクは1バイト(8ビット → 12ビットにエンコード → パディング2文字)です。
Q7:Base64は暗号化の一種ですか?
いいえ。Base64は純粋なエンコーディング方式であり、暗号化ではありません。機密性を全く提供しません——誰でも即座にデコードできます。機密データを「隠す」目的でBase64を使用しないでください。セキュリティのためには実際の暗号化(AES、RSAなど)を使用してください。
Q8:HTTP/2環境でBase64インライン化を過度に使うべきでないのはなぜですか?
HTTP/2は多重化をサポートし、単一のTCP接続で複数のリクエストを同時送信できるため、HTTP/1.1での複数の小リクエストの遅延問題をほぼ解消します。そのため、HTTP/2環境では「リクエスト数を減らす」最適化の価値が大幅に低下し、Base64インライン化によるドキュメントサイズの増大が逆にボトルネックになる可能性があります。