160
174

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Bootstrapのファイルをアップロードするボタンを標準デザインのボタンにする

Last updated at Posted at 2016-12-04

2024年版を書きました


bootstrapを使ってファイルをアップロードするフォームをつくるとき、デフォルトのボタンは小さくて、特にスマホでは表示する際に使いにくいと感じます

こちらの投稿Bootstrap File Inputを使った方法が紹介されています。見た目だけでなく、機能も豊富で参考になります。

ただ今回はbootstrap標準デザインのボタンを使う方法を紹介します。

こちらを参考にしました。


標準の<input type="file">

まず標準の<input type="file">の確認です

<input type="file">
Screen Shot 2016-12-04 at 9.09.52 PM.png

これです。


<span class="btn">で囲んでボタンにする

spanタグで囲むことでbootstrap標準デザインのボタンにできます。inputはstyle="display:none"で隠します。

<span class="btn btn-primary">
    Choose File
    <input type="file" style="display:none">
</span>
Screen Shot 2016-12-04 at 9.40.15 PM.png

このようになります。

ただ、これではクリックしてもファイルを選択できません(Google Chromeで試しました)

さらにlabelタグで囲むと選択できるようになります。コードは下記のようになります。

<label>
    <span class="btn btn-primary">
        Choose File
        <input type="file" style="display:none">
    </span>
</label>

ファイル名を表示する

text-inputを使ってファイル名を表示します。下記のコードをみてください。

<div class="input-group">
    <label class="input-group-btn">
        <span class="btn btn-primary">
            Choose File<input type="file" style="display:none">
        </span>
    </label>
    <input type="text" class="form-control" readonly="">
</div>
Screen Shot 2016-12-04 at 10.57.20 PM.png

まだファイルを選んでも何も表示されません。jqueryを使ってファイル名を表示できるようにします

$(document).on('change', ':file', function() {
    var input = $(this),
    numFiles = input.get(0).files ? input.get(0).files.length : 1,
    label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
    input.parent().parent().next(':text').val(label);
});

おまけ:プレビューを表示する

画像を選択した際にプレビュー表示します。こちらを参考にしました

プレビューを表示するためのdivタグを追加します

<div class="imagePreview"></div>
<div class="input-group">
    <label class="input-group-btn">
        <span class="btn btn-primary">
            Choose File<input type="file" style="display:none" class="uploadFile">
        </span>
    </label>
    <input type="text" class="form-control" readonly="">
</div>
.imagePreview {
    width: 100%;
    height: 180px;
    background-position: center center;
    background-size: cover;
    -webkit-box-shadow: 0 0 1px 1px rgba(0, 0, 0, .3);
    display: inline-block;
}
Screen Shot 2016-12-04 at 10.36.10 PM.png

こうなります。

FileReaderを使って画像を読み込み、divの背景に表示します

$(document).on('change', ':file', function() {
    var input = $(this),
    numFiles = input.get(0).files ? input.get(0).files.length : 1,
    label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
    input.parent().parent().next(':text').val(label);

    var files = !!this.files ? this.files : [];
    if (!files.length || !window.FileReader) return; // no file selected, or no FileReader support
    if (/^image/.test( files[0].type)){ // only image file
        var reader = new FileReader(); // instance of the FileReader
        reader.readAsDataURL(files[0]); // read the local file
        reader.onloadend = function(){ // set image data as background of div
            input.parent().parent().parent().prev('.imagePreview').css("background-image", "url("+this.result+")");
        }
    }
});

後半を追記しています。


サンプル

html全体は下記です。試してみてください

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<style>
    .imagePreview {
        width: 100%;
        height: 180px;
        background-position: center center;
        background-size: cover;
        -webkit-box-shadow: 0 0 1px 1px rgba(0, 0, 0, .3);
        display: inline-block;
    }
</style>
    </head>
    <body>
        <div class="container page-header">
            <div class="col-sm-4">
                <form action="" method="post" enctype="multipart/form-data">
                    <div class="imagePreview"></div>
                    <div class="input-group">
                        <label class="input-group-btn">
                            <span class="btn btn-primary">
                                Choose File<input type="file" style="display:none" class="uploadFile">
                            </span>
                        </label>
                        <input type="text" class="form-control" readonly="">
                    </div>
                </form>
            </div>
        </div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <script>
        $(document).on('change', ':file', function() {
            var input = $(this),
            numFiles = input.get(0).files ? input.get(0).files.length : 1,
            label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
            input.parent().parent().next(':text').val(label);
        
            var files = !!this.files ? this.files : [];
            if (!files.length || !window.FileReader) return; // no file selected, or no FileReader support
            if (/^image/.test( files[0].type)){ // only image file
                var reader = new FileReader(); // instance of the FileReader
                reader.readAsDataURL(files[0]); // read the local file
                reader.onloadend = function(){ // set image data as background of div
                    input.parent().parent().parent().prev('.imagePreview').css("background-image", "url("+this.result+")");
                }
            }
        });
        </script>
    </body>
</html>

追記

最近のBootstrapではjqueryがデフォルトでは動作しないため、別の対策が必要です

ファイルアップロードのボタンに Bootstrap のデザインを適用する

160
174
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
160
174

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?