3.

HTML a要素の download 属性 完全ガイド(ファイル名指定 / 同一オリジン制約 / Blob URL / ブラウザ挙動)

編集
この記事の要点
  • <a download>リンク先をブラウザで開かず、ダウンロード保存させる属性
  • 値を省略するとサーバ側のファイル名download="name.ext" と書けばその名前で保存される
  • 同一オリジン(same-origin)blob: / data: URL のときだけ有効。クロスオリジンの URL では無視されてリンクとして開かれる
  • PDF / 画像などブラウザが普段表示してしまうファイルを強制的にダウンロードさせるのに最適
  • JS で生成したテキスト / CSV / JSON は URL.createObjectURL(blob) + download 属性でファイル保存できる

download 属性とは

<a> 要素の download 属性は、リンク先をブラウザで開かずにダウンロードして保存させるための属性です。PDF や画像のようにブラウザが普段ビューアで表示してしまうファイルを、確実に「保存」として扱わせたい場合に使います。

基本構文

1. ファイル名を指定しない(サーバ側の名前で保存)

<a href="/files/manual.pdf" download>マニュアルをダウンロード</a>

2. ファイル名を指定する

<a href="/files/20260611-abc123.pdf" download="マニュアル.pdf">
  マニュアルをダウンロード
</a>

サーバ上のハッシュ付きファイル名を、ユーザーが見やすい名前で保存させる典型パターンです。

使えるケース・使えないケース

同一オリジンまたは blob: / data: URL のときだけ有効です。クロスオリジンの URL では、ブラウザは安全のため download無視します(通常のリンクとして開く)。

リンク先download 属性
同じドメインのファイル○ 有効(ファイル名指定も可)
blob: URL○ 有効
data: URL○ 有効
別ドメインのファイル× 無視(リンクとして開かれる)
同じドメインに Content-Disposition: attachmentサーバ側が優先

ファイル名指定の挙動

  • download のみ → サーバ側のファイル名(URL 末尾)で保存
  • download="name.ext" → その名前で保存
  • サーバ側で Content-Disposition: attachment; filename="..." がある場合、サーバ側が優先される実装が多い
  • 拡張子は自動補完されない(download="data" なら拡張子なし)
  • OS で使えない文字(/: など)は自動でアンダースコア等に置換される

典型的なユースケース

PDF を「表示」ではなく「保存」させる

ブラウザは PDF をビューアで開いてしまうことが多いですが、download を付けると保存ダイアログが出ます。

<a href="/docs/report.pdf" download>レポートをダウンロード</a>

画像を保存させる

右クリックして保存しなくても、ボタン感覚でダウンロードできます。

<a href="/img/photo.jpg" download="my-photo.jpg">
  写真を保存
</a>

JS で生成したテキストを保存する

BlobURL.createObjectURL で URL 化し、それを download 付きリンクとしてクリックします。CSV / JSON / ログ出力でよく使う定番パターンです。

function downloadText(filename, text) {
  const blob = new Blob([text], { type: "text/plain;charset=utf-8" });
  const url = URL.createObjectURL(blob);

  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(url);   // メモリ解放
}

// CSV をダウンロード
downloadText("data.csv", "name,age\nAlice,30\nBob,25");

data: URL で小さなファイルを保存する

<a href="data:text/plain;charset=utf-8,Hello%20World" download="hello.txt">
  hello.txt をダウンロード
</a>

サーバ側からも強制ダウンロードする

クロスオリジンや確実性が求められる場面では、サーバ側のレスポンスヘッダでダウンロード扱いにします。HTML だけに頼るより堅実です。

Content-Disposition: attachment; filename="report.pdf"
Content-Type: application/pdf

PHP の例:

header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="report.pdf"');
readfile('/var/files/report.pdf');

ブラウザ対応状況

  • Chrome / Edge / Firefox / Safari ともに対応(モダンブラウザ)
  • iOS Safari は仕様上の制約で挙動が独特 — ファイルが新しいタブで開いてしまうケースがある
  • クロスオリジン URL は前述のとおりすべてのブラウザで無視される

セキュリティ上の注意

  • ユーザー入力の値を download に直接埋めない — 拡張子偽装などの攻撃に繋がる可能性
  • 外部 URL に対しては効かない仕様なので、過信しない
  • ダウンロードファイル自体はサーバ側で適切な Content-Type / Disposition を返すのがベストプラクティス

JS から動的にダウンロードを発火する

すでに DOM 上にあるリンクに頼らず、ボタンクリックをトリガに JS でファイルを作って即ダウンロードさせるパターンも頻出です。コードでは「不可視のリンクを作って click() を呼び、すぐ取り除く」のがイディオムです。

async function downloadFromApi(apiUrl, filename) {
  const res  = await fetch(apiUrl);
  const blob = await res.blob();
  const url  = URL.createObjectURL(blob);

  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  a.style.display = "none";
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(url);
}

// 例: API レスポンスを PDF として保存
downloadFromApi("/api/report.pdf", "report.pdf");

ボタンとして見せる

意味的にダウンロードリンクは <a> ですが、見た目をボタン風にするのは CSS だけで完結します。

.download-btn {
  display: inline-block;
  padding: 10px 20px;
  background: #2563eb;
  color: #fff;
  border-radius: 6px;
  text-decoration: none;
  font-weight: bold;
}
.download-btn:hover { background: #1d4ed8; }

関連

  • a 要素 — ハイパーリンク
  • href 属性 — リンク先 URL
  • target 属性 — リンクを開くウィンドウ
  • Blob / URL.createObjectURL — JS でのファイル生成
  • Content-Disposition — サーバ側でのダウンロード指定
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. href属性
  2. target属性
  3. download 属性
  4. rel 属性
  5. hreflang属性
  6. type属性

最近更新/作成されたページ