[CSS] ラベルがにゅっと出る→消えるとコンテンツが表示されているラベルアニメーション
タイトルが意味不明。
こんにちは、ma-ya’s CREATE[まーやずくりえいと]です。
今回は最近見かけるCSSアニメーションについて。
言葉で表現するのがまどろっこしいので、まずはデモを見て下さい。あーアレね!ってなるハズ。
これです。
何もないところにラベルのようなものがにゅっと現れる→ラベルがにゅっと消えていく→コンテンツが表示されている、というやつ。
先日これを実装したんですが、正直ややコード量多めなので自分用のスニペットを作るついでに記事にします。
パパっとコピペで済ませたい方は↑のCodepenをコピペしちゃってください。
JSはリロードボタン以外関係ないので気にしないでOK。
PugとSCSSはCodepen下部の「View Compiled」を押すとそれぞれHTMLとCSSへのコンパイル結果が見れます。
※CSSはコメント部分以降(/* related to css reveal with label from here. */)が今回のアニメーションに関わる部分
親要素・子要素を用意
理想としては要素一つで完結したいところですが、実装の都合上このアニメーションには親要素・子要素を用意する必要があります。
今回はh1の中のテキストをspanでラップしてます。
- 子要素:コンテンツの中身(テキストなど。これ単独で表示非表示を切り替える必要がある)
- 親要素:疑似要素でラベルを生成する。子要素の表示非表示に関わらず、常に表示状態にする必要がある。
何言ってんだこいつ…て感じですね。
まあとりあえずそんなもんだと思ってもらって次いきます(後で触れます)。
各ステップをCSSアニメーションキーフレームで定義、時間差で実行
やるべきことは各ステップをCSSのanimationプロパティで用意(定義)し、それぞれを時間差で実行します。
ステップとしては、
- [パターンA] 中身のコンテンツ(子要素)を非表示に
- [パターンB] ラベル(親の疑似要素)で覆う
- [パターンA] 中身のコンテンツ(子要素)を表示
- [パターンC] ラベル(親の疑似要素)を消す
①③に関しては1つのアニメーションとしてCSSで定義します(だから同じパターンA)。
①③コンテンツの中身(子要素)の表示 / 非表示
コンテンツの中身(子要素)を②が完了するまでは非表示、③が始まる前に表示させるアニメーションは1つのキーフレームアニメーションとして定義します。
span {
animation: fadeIn 0s 0.3s backwards;
@keyframes fadeIn {
0% {
opacity: 0;
}
}
}
今回、ラベルが覆う・消えるアニメーションはそれぞれ0.3sに設定するので、animation-delayの値も0.3sに設定して時間差を作ります。
animation-duration は 0s としていますが、ここの数値を変えるとアニメーションの雰囲気がまた少し変わるのでお試しあれ。
仮にspanを使わず(子要素を作らず)、h1要素のみで実装しようとすると…
その場合、↑のキーフレームアニメーションは必然的にh1自体に当てることになります。すると、h1の疑似要素であるラベルも消えます。
親子要素それぞれ必要なのはこういった理由です。伝わるかなこれ…
②④ラベル(親の疑似要素)で覆う・消す
ここからはCodepenのコードも要参照。
二つのキーフレームアニメーションを用意します。
- ラベルで覆うアニメーション(labelIn)
- ラベルが消えていくアニメーション(labelOut)
この二つのアニメーションを疑似要素に指定。labelOutには時間差も指定します。今回で言えば 0.3s 。
またアニメーションの内容をざっくり言うとこんな感じ↓
- ラベルを transform:scale で伸縮
- 伸縮の方向は transform-origin で制御
transform-origin が最大のポイントですね。
これはtransformで要素を変形させるとき、どこを中心として変形するかを制御できるプロパティです。
これを labelIn の時は left、labelOut の時は right に設定します。
その他のポイントはこちら↓
- 親にposition: relative / 疑似要素に position: absolute でラベルとブロックをぴったり重ねる
- 親には display: inline-block 推奨(場合による)
結論。ラベルアニメーションは意外とめんどくさい。
これに尽きる。
全体でキーフレームを3つ用意して、さらに時間差も気にするとかなーりめんどくさいですね。
コード量もそこそこ多いし。
Sassを使っているならmixin化して時間差は変数で管理しても良いかもしれません。
さらにこういうのはスクロールと連動して発火したい場合が多いと思うので(セクションの見出しとか)、JSスクロールイベントで対象要素にクラスのみ付与すればSassスニペット化したコードでアニメーション発生、とかにすると汎用性も出てくる…のかな?
おまけ:ホバーアニメーションでも同じようなことがしたい場合のサンプル
おまけです。
ラベルで覆う・消すのをホバーイン・ホバーアウトで実現したい場合のホバー版サンプルはこちら。
CSSはキーフレーム版と同様、コメント部分(/* related to css LABEL HOVER from here. */)以降がホバー版に必要な記述です
ホバー版だと単独の要素で実装可能&キーフレームを使わない分だいぶラク。
通常通り、:hover擬似クラスとtransitionで実装します。
ポイント・注意点はこちら↓
- 単独要素で(親子構造にせずとも)実装可能※あくまでデモの動きであれば
- transform-origin でラベルの伸縮方向を制御※キーフレームアニメーション版と同じ
- transition-property はallや未指定にしない(transform をちゃんと指定する)
- 要素自体にz-index:0以上、疑似要素にはz-index:-1を指定
③は注意。アニメーション(特にホバーアウト時)がヘンテコになることがあります。
というかそもそもtransition-propertyは対象のプロパティのみ指定する癖をつけた方が良いです。
慣習で省略したりallにしてばっかりいると原因不明の不具合に悩まされることがあります(僕です)。
④はCSSスタックコンテキストの話が絡むので割愛しますが(そもそも複雑すぎてちゃんと説明できない)、これをしないとテキストの上にラベルが被ります。ホバー版ではラベルを被せることはあまりなさそうなので、こういった仕様にしました。
細かいとこまで書くとキリがないので、今回はこの辺で。
基本的にはCodepenのコードを参照してもらえればと思いますmm
ていうかこういうアニメーション、なんて言うのが正解なんだろ。ラベルアニメーションで良いのだろうか。