ひとりCSS Advent Calendar 2022 16日目です。
input要素をフォーカスしたときにラベルをアニメーションしながら移動させる、を実装しました
Codepen
以下で動きを確認ください。
See the Pen scroll-padding-top by Beco (@becolomochi) on CodePen.
コード解説
HTML
名前とメールアドレスを入力する input を作りました。
<div class="input-group">
<label for="name">name</label>
<input id="name" name="name" type="text" class="input">
</div>
<div class="input-group">
<label for="mail">mail</label>
<input id="mail" name="mail" type="email" class="input">
</div>
label 要素と input 要素をそれぞれ div 要素で囲んでいます。
よく見かけるいつものやつですね。
input 要素には適当なクラス input
をつけていますが JS で操作するためです。
CSS
長くなるので大事な箇所以外は省きました。詳しくは Codepen を見てください。
.input-group {
position: relative;
padding-top: 40px;
}
label {
position: absolute;
transition: 0.2s;
top: 50%;
translate: 0 -50%;
}
.input-group:has(input:focus) label,
.input-group:has(input.filled) label {
top: 0;
}
input {
position: absolute;
top: 0;
width: 100%;
}
- 親要素に
position: relative
とエリアの高さを設定- (padding-top ではなく height のほうが良かったかもしれない…)
- 子要素の label と input に絶対値を指定して位置を決める
- label に transition でアニメーションさせる指定をいれる
-
:has()
を使って、input にフォーカスがあたっているときと入力後に label の位置をずらす指定- 入力後については後述の JS で設定します
- Sass(SCSS) を使えばもっといい感じに省略して書けます
Javascript
input に文字が入力されたかどうかを判定する JS を用意しました。
const inputs = document.querySelectorAll(".input");
inputs.forEach((input) => {
input.onchange = function () {
if (input.value !== "") {
input.classList.add("filled");
} else {
input.classList.remove("filled");
}
};
});
input
クラスのついた項目の入力を見て、何かしら文字が埋まれば filled
クラスを適用します。
入力を終えたあとの input 要素からフォーカスが外れても label 要素は上に移動したままになりました。
これをしないと、label 要素と入力したテキストがかぶって文字が読めなってしまいました。
※JS弱々なのでもっと良い書き方があるかもしれません…
感想
:has() を有効的に使えるサンプルが作れてよかったです。楽しい〜!