こんにちは。KOUKIです。
本記事は、Udemyの「50 Projects In 50 Days – HTML, CSS & JavaScript」で学習したことを載せています。
<目次>
実装するもの
今回は、フォームのラベルにエフェクト(ウェーブ)をつける方法を学習しました。
demoは、「こちら」で確認できます。
環境構築
簡単な環境構築をお願いします。
必要なファイルは、以下の通りです。
1 2 3 4 5 6 |
$ tree . ├── index.html ├── script.js └── style.css |
CSS版
開発
ページの作成
最初にページを作成しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="style.css" /> <title>Form Input Wave</title> </head> <body> <div class="container"> <h1>Please Login</h1> <form> <div class="form-control"> <input type="text" required> <label>Email</label> </div> <div class="form-control"> <input type="password" required> <label>Password</label> </div> <button class="btn">Login</button> <p class="text">Don't have an account? <a href="#">Register</a> </p> </form> </div> <script src="script.js"></script> </body> </html> |
このHTMLをブラウザ上で表示すると以下のようになります。

スタイルの追加
次にスタイルを記述しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap'); * { box-sizing: border-box; } body { background-color: steelblue; color: #fff; font-family: 'Muli', sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; overflow: hidden; margin: 0; } .container { background-color: rgba(0, 0, 0, 0.4); padding: 20px 40px; border-radius: 5px; } .container h1 { text-align: center; margin-bottom: 30px; } .container a { text-decoration: none; color: lightblue; } .btn { cursor: pointer; display: inline-block; width: 100%; background: lightblue; padding: 15px; font-family: inherit; font-size: 16px; border: 0; border-radius: 5px; } .btn:focus { outline: 0; } .btn:active { transform: scale(0.98); } .text { margin-top: 30px; } .form-control { position: relative; margin: 20px 0 40px; width: 300px; } .form-control input { background-color: transparent; border: 0; border-bottom: 2px #fff solid; display: block; width: 100%; padding: 15px 0; font-size: 18px; color: #fff; } .form-control input:focus, .form-control input:valid { outline: 0; border-bottom-color: lightblue; } .form-control label { position: absolute; top: 15px; left: 0; pointer-events: none; } .form-control label span { display: inline-block; font-size: 18px; min-width: 5px; transition: 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); } .form-control input:focus + label span, .form-control input:valid + label span { color: lightblue; transform: translateY(-30px); } |
ここまで実装すると以下のようになります。

JavaScriptの実装
やることは単純です。ラベル(label)要素を取得して、ラベルの文字列(Email/Password)を1文字ずつspanタグに格納後、画面に表示させるだけです。
エフェクトの効果はCSSが半分担いますが、この記事はJavaScriptの記事であるため、詳細は割愛します^^;
要素を取得する
JavaScriptで制御すべき要素が1つあります。最初にその要素を取得しましょう。
1 2 |
// 要素を取得 const labels = document.querySelectorAll('.form-control label') |
spanタグの作成・表示
前述の通り、ラベルにエフェクトをつけるためにspanタグを作成し、画面に表示します。
以下のような感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 取得したラベル文ループを回す labels.forEach(label => { // EmailやPasswordなどラベルに設定されて文字列を取得 let label_innertext = label.innerText // E,m,a,i,lのように1文字ずつ分解(string -> arrayに変わる) label_innertext = label_innertext.split('') // <span>E</span><span>m</span>...のようにspanタグを作成し結合する let span_tags = label_innertext .map((letter, index) => `<span>${letter}</span>`) .join('') // 要素に追加する label.innerHTML = span_tags }) |
ブラウザを開くと以下のようにspanタグが追加されていることがわかります。

「innerHTML」プロパティは、要素内の HTML のマークアップを取得したり設定したりできます。この機能を利用して、labelタグ内にspanタグを追加しました。
また、先ほどのコードは以下のようにスッキリ書くことが可能です。
1 2 3 4 5 6 7 |
// 取得したラベル文ループを回す labels.forEach(label => { label.innerHTML = label.innerText .split('') .map((letter, index) => `<span>${letter}</span>`) .join('') }) |
ラベルにエフェクト(ウェーブ)をつける
demoでみたラベルのエフェクト(ウェーブ)は、CSSで設定した「cubic-bezier」が関係しています。これはイージング関数の一つで、「アニメーションの始めと終わりを緩やかにする」効果を持っています。
現状はフォームをクリックしてもラベルは単一の動きしかしませんが、アニメーションの実行タイミングをずらしてあげるとウェーブを表現できます。
1 2 3 4 5 6 7 8 9 |
labels.forEach(label => { label.innerHTML = label.innerText .split('') .map((letter, index) => `<span style="transition-delay:${index * 50}ms"> ${letter} </span>`) .join('') }) |
spanタグのstyleに「transition-delay」を追加しました。これは、値が変更されたときにプロパティのトランジション効果(アニメーション)が始まるまでの待ち時間を指定します。
これでOKです。
おわりに
開発経験は4~5年ほどありますが、cubic-bezierは初めて知りました^^
「50 Projects In 50 Days – HTML, CSS & JavaScript」はかなり勉強になりますね。
それでは、また!
JavaScriptまとめ
JavaScript ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 要素を取得 const labels = document.querySelectorAll('.form-control label') // 取得したラベル文ループを回す labels.forEach(label => { label.innerHTML = label.innerText .split('') .map((letter, index) => `<span style="transition-delay:${index * 50}ms"> ${letter} </span>`) .join('') }) |
コメントを残す
コメントを投稿するにはログインしてください。