【コピペOK!】マテリアルデザインのテキストフィールドを作る方法

前回の「【コピペOK!】マテリアルデザインのボタンを作る方法」に引き続き、テキストフィールドの作り方を紹介します。

サンプルはこちらに掲載されているので、これをなんとか再現させてみようと思います。

ソースコードの全量はこちらになります。

HTML


<html>
<head>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <style>
        /* 入力欄を構成するパーツをひとくくりにする */
        .md-text-wrapper { 
            position: relative; 
        }

        /* 入力欄 */
        .md-text-input {
            border: none;
            outline: none;
            font-size: 18px;
            padding: 22px 40px 13px 15px;
            border-radius: 4px 4px 0 0;
            border-bottom: 1px solid rgba(0,0,0,.42);
            background-color: #f5f5f5;
        }
        .md-text-input:hover {
            background-color: #eeeded;
        }
        .md-text-input:focus {
            background-color: #dbd9d9;
        }

        /* 項目名 */
        .md-text-label {
            position: absolute;
            left: 15px;
            top: 16px;
            color: #999;
            font-size: 18px;
            pointer-events: none;
            transition: 0.2s ease all;
        }

        /* フォーカスが当たった時の項目名の位置 */
        .md-text-input:focus ~ .md-text-label,
        .md-text-input:required:valid ~ .md-text-label {
            top: 4px;
            color: rgba(98, 0, 238, 0.87);
            font-size: 12px;
        }

        /* 下線 */
        .md-text-bar {
            position: relative;
            display: block;
            width: 100%;
        }
        .md-text-bar:before,
        .md-text-bar:after {
            content: '';
            height: 1px;
            width: 0;
            bottom: 1px;
            position: absolute;
            background: #6200ee;
            transition: 0.2s ease all;
        }
        .md-text-bar:before {
            left: 50%;
        }
        .md-text-bar:after {
            right: 50%; 
        }

        /* フォーカスが当たった時の下線の表示(中心から外側に広がる) */
        .md-text-input:focus ~ .md-text-bar:before,
        .md-text-input:focus ~ .md-text-bar:after {
            width: 50%;
        }

        /* 入力欄右側のアイコン */
        .md-text-icon {
            /* ボタンのスタイルのリセット */
            background-color: transparent;
            border: none;
            outline: none;
            appearance: none;
            cursor: pointer;
            /* 配置 */
            position: absolute;
            bottom: 15px;
            right: 5px;
            color: rgba(0,0,0,.54);
        }

        body {
            display: flex;
            justify-content: center;
            align-items: center;
        }
    </style>
    <script>
        window.onload = function() {
            const button = document.getElementById('myicon')
            button.addEventListener('click', onClickIcon)
        }
        /**
         * アイコンクリック時イベント
         */
        function onClickIcon(event) {
            console.log('アイコンがクリックされました')
        }
    </script>
</head>
<body>
    <div class="md-text-wrapper">
        <input type="text" class="md-text-input" required>
        <span class="md-text-bar"></span>
        <label class="md-text-label">Label</label>
        <button id="myicon" class="md-text-icon">
            <i class="material-icons">search</i>
        </button>
    </div>
</body>
</html>

では以下に解説していきます。

HTML

HTML


<div class="md-text-wrapper">
   <input type="text" class="md-text-input" required>
   <span class="md-text-bar"></span>
   <label class="md-text-label">Label</label>
   <button id="myicon" class="md-text-icon">
       <i class="material-icons">search</i>
   </button>
</div>

画面上では一つのテキストフィールドなんですけど、HTMLで見るといくつかのタグを組み合わせていることがわかります。

inputタグ

入力フォームです。ここに文字を入力します。通常のテキストフィールドであればこのタグだけで十分です。

spanタグ

テキストフィールドをクリックした時に中央から端に向かってびょーんと伸びる下線です。

labelタグ

項目名です。未入力の時は中央に表示されますが、入力中や入力済の時はちっちゃくなって上のほうに移動します。

buttonタグ

入力欄の右側に表示されているアイコンを包むボタンです。不要な場合は消しちゃって大丈夫です。

iタグ

アイコンです。ここでは例としてマテリアルアイコンに用意されている検索アイコンを使っています。

iタグにmaterial-iconsというクラス名を付与してアイコンに合うテキストを書けばアイコンが表示されます。

また、マテリアルアイコンを使うには以下を読み込んでおく必要があります。

HTML


<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

CSS

CSS


/* 入力欄を構成するパーツをひとくくりにする */
.md-text-wrapper { 
   position: relative; 
}

テキストフィールドを構成する各タグはmd-text-wrapperというクラスが付与されたdivタグでまとめられています。

項目名やアイコンなどがposition: absoluteで絶対配置になるので、親となるdivタグからはみ出ないよう、ここではposition: relativeが設定されています。

CSS


/* 入力欄 */
.md-text-input {
   border: none;
   outline: none;
   font-size: 18px;
   padding: 22px 40px 13px 15px;
   border-radius: 4px 4px 0 0;
   border-bottom: 1px solid rgba(0,0,0,.42);
   background-color: #f5f5f5;
}
.md-text-input:hover {
   background-color: #eeeded;
}
.md-text-input:focus {
   background-color: #dbd9d9;
}

md-text-inputクラスはinputタグに設定したクラスです。

border、outlineにnoneを設定して余計な枠線を消しています。もしリセットCSSを導入している場合はこの記述はいらないかもしれません。

paddingで入力欄の内側の余白を設定しています。上が22px、右が40px、下が13px、左が15pxです。

border-radiusで右上、左上の角を少し丸めています。右下、左下は丸めたくないので0を設定しています。

border-bottomは入力欄の下線を表現していますが、入力中に表示される太めの下線ではなく、触ってない時に表示されるグレーの下線になります。

背景色は最初薄いグレー(#f5f5f5)ですが、カーソルを当てるとちょっと濃く(#eeeded)、クリックして編集中の時はさらに濃く(#dbd9d9)なるようにしています。

CSS


/* 項目名 */
.md-text-label {
   position: absolute;
   left: 15px;
   top: 16px;
   color: #999;
   font-size: 18px;
   pointer-events: none;
   transition: 0.2s ease all;
}

/* フォーカスが当たった時の項目名の位置 */
.md-text-input:focus ~ .md-text-label,
.md-text-input:required:valid ~ .md-text-label {
   top: 4px;
   color: rgba(98, 0, 238, 0.87);
   font-size: 12px;
}

こちらは項目名を表示するlabelタグのスタイル設定になります。

inputタグの上に被さるように表示するのでposition: absoluteで絶対配置となります。

leftとtopで位置を決めています。

pointer-events: none;としているのは項目名部分のクリックを素通りさせるためです。

これがないと項目名をクリックしても入力欄がアクティブになりません。項目名を避けてクリックすればアクティブになりますが、それはユーザーにとって不便なだけなので項目名へのクリックを無効化してinputタグがクリックされるようにしています。

inputタグがクリックされると項目名は小さくなって上のほうに移動しますが、その移動スピードをtransitionで設定しています。

以下の「.md-text-input:focus ~ .md-text-label」の「~」は見慣れない方もいるかもしれません。

「A ~ B」というのはA要素の後に来る同じ階層のB要素に対するスタイルを意味しています。

なのでinputタグがクリックされた時のその後続の同階層にあるlabelタグに対するスタイルということになります。

また「.md-text-input:required:valid ~ .md-text-label」の「:required」は擬似クラスといってrequired属性が設定されているタグを意味し、「:valid」は正しく入力されたタグを意味します。

どちらも同じスタイルを適用していますが、ここでやりたいことは「inputタグがクリックされた時、もしくは入力欄に入力されている時に項目名をちょっと小さくして上のほうにずらして、文字色を変える」ということです。

CSS


/* 下線 */
.md-text-bar {
   position: relative;
   display: block;
   width: 100%;
}
.md-text-bar:before,
.md-text-bar:after {
   content: '';
   height: 1px;
   width: 0;
   bottom: 1px;
   position: absolute;
   background: #6200ee;
   transition: 0.2s ease all;
}
.md-text-bar:before {
   left: 50%;
}
.md-text-bar:after {
   right: 50%; 
}

/* フォーカスが当たった時の下線の表示(中心から外側に広がる) */
.md-text-input:focus ~ .md-text-bar:before,
.md-text-input:focus ~ .md-text-bar:after {
   width: 50%;
}

こちらはinputタグをクリックした時にびょーんと伸びる下線のスタイルです。

spanタグを使って表現しますが、spanタグの間には何も文字が書かれていないので通常何も見えません。

ではあの伸びる下線はどこで表現しているかというと:before、:afterという擬似要素になります。

:beforeは指定の要素の前に擬似的な要素を作りますという意味になります。

:afterはその逆で要素の後ろに擬似的な要素を作ります。

下線は中心から左端、右端に広がっていきますが、左端に広がる下線を:beforeが、右端に広がる下線を:afterの擬似要素が担っています。

一つずつ見ていくと、

まずspanタグはdisplay: blockによってインライン要素からブロック要素に変更しています。

そしてwidth: 100%によってinputタグの横幅と同じだけの幅を持たせます。

その後、:beforeと:afterには基本的に同じスタイルが設定されていますが、

contentには前後に表示したい文字を設定します。しかし今回は下線が出ればよく文字はいらないので空文字を設定しています。

height: 1pxは下線の高さ

width: 0は横幅0。つまり初期状態では見えないこととしています。

position: absoluteとbottom: 1pxによってinputタグの下から1pxの場所に線が引かれるようになります。

:beforeにはleft: 50%、:afterにはright: 50%を設定することによってスタート位置をそれぞれinputタグの中心になるよう設定しています。

最後の「md-text-input:focus ~ .md-text-bar:before」 「md-text-input:focus ~ .md-text-bar:after」によってinputタグがクリックされた時にそれぞれの下線の横幅をinputタグの半分に設定することで:beforeの擬似要素が左半分を、:afterの擬似要素が右半分を埋めます。

transitionが0.2秒で設定されているので0.2秒かけて中心から端っこに向かってアニメーションをするように広がっていきます。

JavaScript

JavaScript


window.onload = function() {
   const button = document.getElementById('myicon')
   button.addEventListener('click', onClickIcon)
}
/**
 * アイコンクリック時イベント
 */
function onClickIcon(event) {
   console.log('アイコンがクリックされました')
}

こちらはアイコンがクリックされた時にonClickIcon関数が呼ばれるように設定しているだけです。

何か処理をしたい時はonClickIcon関数の中を好きに実装してください。

まとめ

以上がマテリアルデザインのテキストフィールドの作り方でした。

おしゃれで見やすいと思うのですが、難点を挙げるとするとこの入力欄は高さを結構取ります。

あるプロジェクトで取り入れた時に「もっと画面に情報きゅっと詰め込みたい」と言われた時にガビーンとなりました。。

あとは普通のテキストフィールドであればinputタグだけで済むのにラベルだったり下線だったりいろいろなタグを駆使して実現しているので、ソースコードが煩雑になりがちです。

入力欄がたくさん必要なページだとちょっと悲惨な結果になりそうですよね。

Vue.jsなどのフレームワークを採用できるのであれば上記のソースコードをコンポーネント化して、それを呼び出すなどの工夫をするのがベターです。

入力欄のデザインはこの限りではないですが、興味のある方は上記のソースコードを参考に必要に応じて調整して取り入れてみてください。

したっけ!

本格的にプログラミングを学びたいですか?ITのエンジニアになりたいですか?

IT業界は万年人手不足であり、ニーズがあります。
パソコンとインターネットがあれば場所を問わず仕事ができるので、リモートワークが普及しつつある現代にマッチした職種と言えると思いますし、 物理的に必要なものはパソコンぐらいなので初期投資にかかる費用も少なく、人並みに仕事ができればフリーランスになって会社依存を脱却することもできます。

身につけた技術は一生モノです。

もし本腰を入れて勉強したいという方はスクールに入るのも一つの手です。
いくつか紹介しますので、興味があればサイトを覗いてみてください。

DMM WEBCAMP

転職を本気で考えている方向けのプログラミングスクールです。 転職を保証しているため、未経験からIT業界へ転職を求めている方へおすすめです!

DMM WEBCAMPのサイトへ

TechAcademy

最短4週間で未経験からプロを育てるオンライン完結のスクールです。 どこかに通う必要なく、自宅でもプログラミングやアプリ開発を学ぶことができます。

TechAcademyのサイトへ

Want to learn programming in earnest? Want to be an IT engineer?

The IT industry is understaffed for many years and has needs.
If you have a computer and the Internet, you can work anywhere, so I think it can be said that it is a job type that matches the present age when remote work is becoming widespread. The initial investment cost is low, and if you can work like a normal person, you can become freelance and get rid of your dependence on the company.

The skills that you have acquired is something that will last a lifetime.

If you want to study in earnest, you can go to school.
I will introduce some of them, so if you are interested, please take a look at the site.

DMM WEBCAMP

This is a programming school for those who are serious about changing jobs. guarantee a job change, so it is recommended for those who are inexperienced and are looking for a job change in the IT industry!

move to DMM WEBCAMP

TechAcademy

It is an online school that trains professionals from inexperienced in a minimum of 4 weeks. You can learn programming and app development at home without having to go anywhere.

move to TechAcademy