• Web制作
  • CSSとJavaScriptを使ったinputタグのカスタマイズ

CSSとJavaScriptを使ったinputタグのカスタマイズ

草野あけみさんが書かれた「HTML+CSS コーディングの強化書」を使って学習しているのですが、フォーム部分で、うまく動作しない箇所がありました。

Webサイトでファイルをアップロードしたいとき、「<input type=”file”>」を使ってシステムに渡すのですが、書籍でも触れられているようにブラウザごとに外観が異なり、デフォルトのままだとチョット統一感のない見た目になってしまいます。

これまで、この見た目は修正できないと思っていて、そのままの形で使っていたのですが、CSSを使ったカスタマイズ方法が書籍で紹介されており、さっそく試してみました。
ですが、わたしが想定しているように動いてくれませんでした。

実際のコードは掲載したらマズいと思うので、キャプチャでの確認になりますが、サンプルデータをブラウザで開いてみると、このような外観になります。

この状態だと普通のボタンのように見えますが、実際は「<input type=”file”>」をベースにして、CSSで見た目を変えています。また、inputタグはlabelタグでマークアップされており、そのlabelタグに「tabindex=”0″」が設定されています。

この「tabindex」は、HTMLを勉強したての方だと初めて聞いた人もいるかもしれませんが、TABキーを押したときに、何番目にフォーカスされるかを指定するプロパティです。つまり、「tabindex=”0″」を設定すると、TABキーを押したときに、一番目にフォーカスされ、今回のサンプルでは、labelタグがフォーカスされます。

実際にサンプルページでTABキーを押すと、このように外枠に色が付きます。

見えにくいかもしれませんが、ボタンの周囲にborderが表示されています。

ですが、この状態でエンターキーを押してもinputは動作せず、もう一度TABキーを押してエンターキーを押さないと、ファイルの選択画面が開かないようになっています。

また、ボタンの右側をクリックすると、全然関係のない場所のはずですが、ファイルの選択画面が開いてしまいます。

ボタンの右側をクリックしても、選択画面が開きます。

開発者ツールを使って確認すると、inputの横幅がlabelタグをはみ出して拡がっており、その結果、何もない部分でもクリックできるようになってしまっているようです。

このように、見た目と動作が異なってしまい、サイト訪問者が混乱してしまうかもしてません。

ですが、せっかくCSSでデザインできることを知ったので、JavaScriptを使うことになりますが、わたしなりにコードを改良してみました。

CSSとJavaScriptを使ったinputデザイン

こちらが、今回アレンジしたソースコードです。

クリックするとサンプルページが開きます。
<style>
    input[type="file"] {
        opacity: 0;
        position: absolute;
        width: 1px;
    }

    .fileUpload {
        width: 12rem;
        padding: 10px 20px;
        text-align: center;
        display: block;
        background: #59a13d;
        color: #ffffff;
        cursor: pointer;
    }

    .fileUpload:focus {
        outline: 2px solid #bace61;
    }
</style>
<label id="fileWrap" for="upload" class="fileUpload" tabindex="0">
    <input type="file" name="file" id="upload">
    画像ファイルを選択
</label>
<p id="fileName">選択されていません</p>

<script>
    document.addEventListener('DOMContentLoaded', function () {

        // label要素を取得
        const lavelElement = document.getElementById('fileWrap');

        // fileアップロード用のinput要素を取得
        const inputElement = document.getElementById('upload');

        // ファイル名を表示させるp要素を取得
        const fileNameText = document.getElementById('fileName');

        // Enterキーを押して、かつid「fileWrap」にフォーカスしている時に、inputを動作
        document.onkeydown = function (event) {
            if (event.key === 'Enter' && document.activeElement.id === 'fileWrap') {
                inputElement.click();
            }
        }

        // inputが変化したときの動作
        inputElement.addEventListener('change', function () {

            const imageName = inputElement.files[0];
            fileNameText.innerText = imageName.name;
        });

    });
</script>

まず、今回のJavaScriptは、jQueryのようなライブラリは使わず、素のJSだけで考えてみました。流れとしては、こんな感じになっています。

要素部分の取得

まず、idを使って、「label」タグ、「input」タグ、ファイル名を表示させる「p」タグの要素を取得します。

// label要素を取得
const lavelElement = document.getElementById('fileWrap');

// fileアップロード用のinput要素を取得
const inputElement = document.getElementById('upload');

// ファイル名を表示させるp要素を取得
const fileNameText = document.getElementById('fileName');

JavaScriptを使って、inputタグを動作させる

次に、エンターキーを押した時に、ファイル選択画面を開くように「<input type=”file”>」を動作させます。
とはいっても、日本語を入力して確定させるときもエンターキーを使うので、『エンターキーを押して、かつ「label」タグにフォーカスが当たっている』という条件が成立するときに動作するようにしています。

// Enterキーを押して、かつid「fileWrap」にフォーカスしている時に、inputを動作
document.onkeydown = function (event) {
    if (event.key === 'Enter' && document.activeElement.id === 'fileWrap') {
        inputElement.click();
    }
}

選択したオブジェクトからファイル名を取得

今回のサンプルでは、選択した画像名も表示させるようにしています。具体的には、「input」の状態が変化したときに、選択したファイルの名称を取得し、下のpタグの中に入れるようにしています。

// inputが変化したときの動作
inputElement.addEventListener('change', function () {
    const imageName = inputElement.files[0];
    fileNameText.innerText = imageName.name;
});

アクセシビリティーはどうなのだろう?

このように、見た目をCSSで変えて、かつキーボードでも操作できるようにアレンジしてみました。ですが、JavaScriptを使っているので、アクセシビリティーの面からどうなのか、チョット不安があります。また、inputタグがlabelタグからはみ出さないように、widthを「1px」にしています。目に見えなくても動作するようにしたのですが、これも大丈夫なのか、不安があります。

ですので、改めて考えると、見た目は整わなかったとしても、通常のデフォルト表示の方が実はいいかもしれませんね。

参考サイト

今回のサンプルを作るにあたって、こちらのサイトを参考にさせてもらいました。

関連記事