HTMLの<input type="file">
はファイルのアップロードボタンを設置するために使います。
<input type="file" name="example" accept="image/jpeg, image/png">
Webアプリケーションで画像などのアップロードの仕組みを作るときには欠かせません。ぜひ基本的な使い方をマスターしましょう。
ブラウザごとの表示や挙動
<input type="file">
はIE含めて主要ブラウザすべてで使用できます。[ファイルを選択]ボタンをクリックすると、ファイルの選択ウィンドウが開きます。
📱モバイル端末でも使用可能
Androidのブラウザでも同じように端末内の画像を選択できます。このように、モバイルのブラウザからでもファイルのアップロードが可能です。
input type="file"の使い方
formで送信する例
まず、ごく簡単なサンプルHTMLを紹介します。JavaScriptは使わずに、<form>
でサーバーへデータを送る例です。
<form method="post" enctype="multipart/form-data">
<input type="file" name="avatar">
<button type="submit">送信する</button>
</form>
👆name
属性でフィールドの名前を指定します。この名前があることでサーバーへ送信したときに「どの情報が、どのフィールドに対応しているのか」分かります。
name="avatar"
なので、サーバーではファイルの情報はavatar
に紐付いていることが分かるわけですね。
ファイルをサーバーに送るときには、<form>
タグにmethod="post"
やenctype="multipart/form-data"
という属性を指定する必要があります。
method="post"
デフォルトではmethod="get"
となっています。get
だとフォームの内容はURLにくっつく形(https://example.com?フィールド名=値
)で送られます。テキストデータならこれで良いのですが、ファイルの中身はURLに含めることができません。
そこでmethod="post"
を使うと、送信内容が(URLに付くのではなく)本文として送られます。post
ならファイルでも送信できるのです。
enctype="multipart/form-data"
詳しい解説はここでは省略しますが、<form>
にenctype="multipart/form-data"
を指定すると、フォームデータの中に、文字列だけでなく様々な形式のデータを含めることが可能になります。
この方法だと、送信ボタンをクリックした時にページが遷移します。ページを切り替えることなくその場でファイルをアップロードしたい場合は、JavaScriptを使ってファイルを操作しましょう(のちほど解説します)。
accept属性:アップロード可能なファイル形式を制限する
accept
属性では、受け付けるファイルの拡張子や種類を指定できます。複数指定するときは半角カンマ(,
)で区切って並べます。
<input type="file" name="example" accept=".png, .jpg, .jpeg, .pdf, .doc">
👆accept="◯◯"
に指定されている.png
、.jpg
、.jpeg
、.pdf
、.doc
の拡張子のファイルを選択できるようになります。
こちらはMacのファイル選択ウィンドウです。accept="◯◯"
に指定されていない拡張子のファイルは選択できません。
MIMEタイプでの指定してもOK
「MIMEタイプ」とは、ブラウザとサーバー間のやり取りで使われるファイル種類を表す情報のことです。たとえばPNG画像をMIMEタイプで表すとimage/png
となります。拡張子.jpg
と.jpeg
はimage/jpeg
という1つのMIMEタイプでまとめられます。
つまり、次の2つは同じ意味になります。
accept=".png, .jpeg, .jpg"
accept="image/png, image/jpeg"
画像ファイル全般を許可する場合
<input type="file" name="example" accept="image/*">
👆「画像ファイルなら選択可」という場合にはimage/*
と指定します。
multiple属性:複数ファイルを選択可能にする
input
タグにmultiple
属性を指定すると、複数のファイルの選択が可能になります。
<input type="file" name="example" accept="image/*" multiple>
このように複数のファイルをまとめて選択できるようになります。
required属性:ファイルの選択を必須にする
<form>
<input type="file" name="avatar" required>
<button type="submit">送信する</button>
</form>
このまま送信するとエラーに
👆<input>
タグにrequired
を指定すると、ファイルの選択が必須になります。選択されていない場合は、送信時にブラウザによりエラーが表示されます。
ただし<form>
タグ内に<input>
と送信ボタンがある場合にのみ、エラーが表示されます。また、JavaScriptでファイルを送る場合は、このエラーは表示されないので注意しましょう。
JavaScriptで選択されたファイルデータを取得する
File APIというものを使えば、JavaScriptでより自由にファイルを操作できます。独自のバリデーションや、非同期アップロードなども実現できます。
まずは、1つ〜複数のファイルが選択されたときに、1つ1つのファイルデータ(Fileオブジェクト)を取得してみたいと思います。HTMLではmultiple
で複数選択できるようにします。
HTML
<input type="file" id="example" multiple>
JavaScript
// input要素
const fileInput = document.getElementById('example');
// changeイベントで呼び出す関数
const handleFileSelect = () => {
const files = fileInput.files;
for (let i = 0; i < files.length; i++) {
console.log(files[i]); // 1つ1つのファイルデータはfiles[i]で取得できる
}
}
// ファイル選択時にhandleFileSelectを発火
fileInput.addEventListener('change', handleFileSelect);
👆input要素.addEventListener('change', 関数)
により、フィールドの値が変更された時(≒ファイルが選択された時)に関数を実行できます。
ファイルデータ一覧はinput要素.files
により取得できます。ループ処理によりその中身を1つ1つ取り出しています(今回は単にコンソールに出力するだけにしました)。
たとえばJPEG画像を2枚選択した場合、コンソールの出力結果(つまりfiles[i]
の中身)はこのようになります。
Fileオブジェクトの内容
- name:ファイル名
- size:ファイルのサイズ(Byte)
- type:ファイルのMIMEタイプ
- lastModifiedDate:ファイルの最終更新日
たとえば、ファイル名はfiles[i].name
で、ファイルサイズfiles[i].size
で取得できます。
ファイルサイズを制限する
次に「ファイルサイズが一定サイズ以上の場合、エラーメッセージを出して終了する」ということをやってみましょう。ここでは制限サイズを1MBとします(Byteで表すと1024 * 1024 * 1
)。
HTML
<input type="file" id="example" multiple>
JavaScript
const sizeLimit = 1024 * 1024 * 1; // 制限サイズ
const fileInput = document.getElementById('example'); // input要素
// changeイベントで呼び出す関数
const handleFileSelect = () => {
const files = fileInput.files;
for (let i = 0; i < files.length; i++) {
if (files[i].size > sizeLimit) {
// ファイルサイズが制限以上
alert('ファイルサイズは1MB以下にしてください'); // エラーメッセージを表示
fileInput.value = ''; // inputの中身をリセット
return; // この時点で処理を終了する
}
}
}
// フィールドの値が変更された時(≒ファイル選択時)に、handleFileSelectを発火
fileInput.addEventListener('change', handleFileSelect);
👆大まかな流れは、さきほどのサンプルと同じです。1つ1つのファイルデータのサイズ(Byte数)はfiles[i].size
で取得できます。これを上限サイズの値と比較しているわけですね。
エラー時にはfileInput.value = '';
でフィールドをリセットしています。これをやらないと、後で同ファイルが選択されたときにボタンが反応しなくなってしまいます。
CodePenのサンプルも貼り付けておきます。
👆1MB以上のファイルをアップロードしようとすると「ファイルサイズは1MB以下にしてください」というエラーメッセージが表示されます。
😿少し詳しい人がやろうと思えば、制限サイズ以上のファイルをサーバーに送りつけることも可能です。サーバー側でもファイルサイズをチェックするのが良いでしょう。
画像のプレビューを表示する
<input type="file">
で画像が選択されたときに「プレビューを表示したい」というのはよくあることだと思います。こちらはFileReaderを使えば実現できます。
FileReader
FileReader
は、ファイルを読む込むための仕組み(API)です。FileReader
のreadAsDataURL()
というメソッドを使うと、ファイルデータをURLとして読み込んでくれます。
画像の情報を1つのURLにまとめるため、とっても長いURLになります。
詳しくはFileReader - MDNが参考になります。
複数枚の画像プレビューに対応したサンプルコード
HTML
<input type="file" id="example" multiple>
<!-- 👇ここにプレビュー画像を追加する -->
<div id="preview"></div>
JavaScript プレビュー関数
function previewFile(file) {
// プレビュー画像を追加する要素
const preview = document.getElementById('preview');
// FileReaderオブジェクトを作成
const reader = new FileReader();
// URLとして読み込まれたときに実行する処理
reader.onload = function (e) {
const imageUrl = e.target.result; // URLはevent.target.resultで呼び出せる
const img = document.createElement("img"); // img要素を作成
img.src = imageUrl; // URLをimg要素にセット
preview.appendChild(img); // #previewの中に追加
}
// いざファイルをURLとして読み込む
reader.readAsDataURL(file);
}
👆ファイルデータ(file
)を渡すとプレビュー画像をid="preview"
要素の中に追加する関数です。reader.onload = function (e) { ... }
の部分でURLを受け取り、画像要素を作成し、HTMLに追加しています。
完全なサンプルコード
CodePenのサンプルも用意しました。画像選択時にファイルデータを取得し、previewFile
関数にわたすところまでやっています。実際に画像プレビューが表示されることを確認してみてください。
JavaScriptで画像を送信する 中級者向け
非同期で画像データをサーバーに送信するやり方はいくつかあります。ライブラリを使わずにやるなら、FormDataで作成したフォームデータを、Fetchで送信するのが簡潔でしょう。
JavaScript ファイルデータを送信
// ファイルデータ
const file = document.getElementById("example").files[0];
// フォームデータを作成
const formData = new FormData();
// avatarというフィールド名でファイルを追加
formData.append("avatar", file);
// アップロード
fetch(送信先のURL, { method: "POST", body: formData });
👆大まかな流れです。実際のアプリケーション開発では「async/await
で非同期処理にする」「try/catch
でエラーハンドリングする」なども必要になるでしょう。
CSSでボタンのデザインをカスタマイズ
<input type="file">
で表示されるアップロードボタンの見た目は、CSSでカスタマイズできます。
サンプルコード
HTML
まずHTMLは次のようにします。
<label class="upload-label">
ファイルを選択
<input type="file">
</label>
👆<label>
タグで<input type="file">
を囲むことにより、<label>
をクリックすればファイルの選択ウィンドウが開くようになります。デフォルトの選択ボタン(<input>
)をCSSで隠してしまっても、<label>
が選択ボタンの役割をしてくれるわけですね。
CSS
<label>
のクラスupload-label
に対してCSSでスタイルをあてていきます。
/* labelをボタンらしく */
.upload-label {
display: inline-block;
cursor: pointer; /* カーソルを指に */
margin: 1em 0; /* まわりの余白 */
padding: .7em 1em; /* 文字まわりの余白 */
line-height: 1.4; /* 行間 */
background: #3e8bff; /* 背景色 */
color: #FFF; /* 文字色 */
font-size: 0.95em; /* フォントサイズ */
border-radius: 2.5em; /* 角の丸み */
transition: 0.2s; /* ホバーをなめらかに */
}
/* ホバー時 */
.upload-label:hover {
box-shadow: 0 8px 10px -2px rgba(0, 0, 0, 0.2); /* 影を表示 */
}
/* inputは隠す */
.upload-label input {
display: none;
}
クリックでファイル選択が開く
👆デフォルトの<input>
の見た目を変えるのは難しいので非表示にしてしまいます。そのうえで<label>
を装飾し、ボタンらしく見せています。
その他の種類の<input>
の使い方はこちらのページで解説しています。
こちらはiOS Safariでの表示例です。[ファイルを選択]⇒[フォトライブラリ]とタップすれば、端末内の画像を選択できます。