プログラミング初心者の勉強ブログ #105
CSSアウトプットを兼ねて、実在サイトのCSSアニメーションを考察していきます。@keyframesとanimationプロパティを用いて、実際に存在するサイトではどのようなデザインが作られているか把握し、コードを見て作れるようになることで、今後のオリジナルWebサイトのUI向上を図っていきます。
目次
[toc]
今回の参考サイト
今回参考にするのはヘアケアメーカー「ナプラ」のリクルートサイトです。開いてすぐ、がっつりアニメーションが動き出します。コードを確認したら、@keyframesとanimationプロパティが色々と書いてあり、ギリギリわかりそうだったので選定しました。(JSは読み解くの難しすぎます。20個以上に分割された関数のまとまりがオブジェクト型として引数に渡されており、thisが何のthisなのか追うのが難しいです。フレームワークの構造?なのかもしれないので、reactとかvueとかやったことあれば少しはわかるものなのかもしれません。とりあえずCSSアニメーションを抽出して仕組みを理解していきます。)
真似するアニメーション
今回考察するのは、上の画像のような見出し部分の表示です。 最初にラインが描画され、ラインが消えるとともに文字が表示されます。
作業工程としては、
- ラインの表示・非表示
- 文字「MESSAGE」の表示
の2つですが、アニメーション構造はもう少し複雑に構成されてます(具体的には@keyframesを3つ使用されてます)。いかにして文字を流れるように表示させる表示を構成しているかが、今回のアニメーションのポイントになります。
アニメーション構造の考察
構造を整理するために、「ラインの表示・非表示」と「文字の表示」を分けて考えます。
ラインの表示・非表示
まずはラインの表示・非表示についてです。コードを確認したところ、「borderInOut」という@keyframesで設定したアニメーション一つで、ラインを書いたり消したりしています。以下ソースコードの抜粋です。
main.css
// ラインを表示させるdiv擬似要素 .c-border-in-out.is-animate .c-border-in-out__content:after, .c-border-in-out.is-shown .c-border-in-out__content:after { # 下で設定した@keyframesをセット -webkit-animation-name: borderInOut; animation-name: borderInOut; # 一回のアニメーションにかかる時間を設定 -webkit-animation-duration: .8s; animation-duration: .8s; # アニメーション終了後のスタイルを100%時のスタイルで保持 -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards } // ラインを表示させるアニメーション設定 @keyframes borderInOut { # 最初の状態 0% { opacity: 0; -webkit-transform: scaleX(0); transform: scaleX(0); -webkit-transform-origin: left; # アニメーションの原点を左に transform-origin: left } # 開始5%後、opacityを上げる 5% { opacity: 1; -webkit-transform: scaleX(0); transform: scaleX(0); -webkit-transform-origin: left; transform-origin: left } # scaleXを1にすることで、width全域にラインを表示 49% { opacity: 1; -webkit-transform: scaleX(1); transform: scaleX(1); -webkit-transform-origin: left; transform-origin: left } # アニメーション原点を今度は右へ 50% { opacity: 1; -webkit-transform: scaleX(1); transform: scaleX(1); -webkit-transform-origin: right; transform-origin: right } # scaleを0に戻すことでラインが消える 100% { opacity: 1; -webkit-transform: scaleX(0); transform: scaleX(0); -webkit-transform-origin: right; transform-origin: right } }
※「-webkit」はベンダープレフィックスです。Chromeやsafari対応用です。詳しくは自分で調べてください。
上のコードのように、opacityが1、scaleXが1になるにつれて、ラインが現れます。
コードを見て不思議に思ったのが、「transform: scaleX( )」を使っている点です。ラインを伸ばす場合、widthを0%→100%にしてdurationをつければそれでも大丈夫なのでは、と思っていたのですが、
// widthの場合(例) 0% { opacity: 0; width: 0; -webkit-transform-origin: left; transform-origin: left } 49% { opacity: 1; width: 100%; # ライン幅を100%に変化させることで伸ばす transform-origin: left } # 省略
これだと「transform-origin」でアニメーションの原点を変更できませんでした。
「原点」とは、アニメーションが実行されるにあたって基準となる軸のことです。
詳しくは上のリンクから確認してください。この原点を変更しないと、ラインを消すアニメーションが想定した挙動になりません。
文字の表示
次に文字の表示です。こちらでは2つの@keyframesを組み合わせてアニメーションが構成されています。
イメージとしては、
親子関係のdivを2つ用意し、親要素のdivに「overflow: hidden」をかけることで、2つのdivが重なっている部分のみが表示されることを利用した構造となっております。
// 親要素divのアニメーション @keyframes contentWrapMove { 0% { opacity: 0; -webkit-transform: translateX(-100%); transform: translateX(-100%) } 5% { opacity: 1; -webkit-transform: translateX(-100%); transform: translateX(-100%) } 100% { opacity: 1; -webkit-transform: translateX(0); transform: translateX(0) } } // 子要素divのアニメーション @keyframes contentInnerStay { 0% { -webkit-transform: translateX(-100%); transform: translateX(-100%) } 5% { -webkit-transform: translateX(-100%); transform: translateX(-100%) } 100% { -webkit-transform: translateX(0); transform: translateX(0) } }
実際に真似して作成してみた
とりあえず真似して作成してみたので、コードを載せます。
index.html(抜粋)
<div class="tp">supunic <div class="border"> <div class="hidden"> <div class="inner">supunic</div> </div> </div> </div>
styles.css
// 初期スタイル設定 ----------------------------- // 大枠としてdivを用意(文字は表示させない) .tp { margin-top: 320px; white-space: nowrap; display: inline-block; color: transparent; position: relative; font-size: 100px; font-family: 'Akzidenz Grotesk'; font-weight: 500; font-smoothing: antialiased; -webkit-font-smoothing: antialiased; } // ライン表示用のdiv .border { display: inline-block; position: absolute; top: 0; left: 0; margin: 0; padding: 0; } // 実際にラインを表示する擬似要素 .border:after { content: ""; display: inline-block; height: 10%; position: absolute; top: 50%; right: 0; left: 0; transform: translateY(-50%); background-color: #333; transform: scaleX(0); opacity: 0; animation-name: borderInOut; animation-duration: 1s; animation-timing-function: ease-out; animation-fill-mode: forwards; } // 文字表示用親要素 .hidden { width: 100%; height: 100%; display: block; overflow: hidden; transform: translateX(-100%); opacity: 0; animation-name: contentWrapMove; animation-duration: .7s; animation-timing-function: ease-out; animation-fill-mode: forwards; animation-delay: 0.5s; } // 文字表示用子要素 .inner { font-size: 100px; color: #333; transform: translateX(100%); opacity: 0; animation-name: contentInnerStay; animation-duration: .7s; animation-timing-function: ease-out; animation-fill-mode: forwards; animation-delay: 0.5s; font-family: 'Akzidenz Grotesk'; font-weight: 500; letter-spacing: .05em; } // アニメーション設定 ------------------------------ // 文字表示用(親要素の移動) @keyframes contentWrapMove { 0% { transform: translateX(-100%); opacity: 0; } 1% { transform: translateX(-100%); opacity: 1; } 100% { transform: translateX(0); opacity: 1; } } // 文字表示用(子要素の移動) @keyframes contentInnerStay { 0% { transform: translateX(100%); opacity: 0; } 1% { transform: translateX(100%); opacity: 1; } 100% { transform: translateX(0); opacity: 1; } } // ライン表示・非表示用 @keyframes borderInOut { 0% { transform: scaleX(0); opacity: 0; transform-origin: left; } 1% { transform: scaleX(0); opacity: 1; transform-origin: left; } 49% { transform: scaleX(1); opacity: 1; transform-origin: left; } 50% { transform: scaleX(1); opacity: 1; transform-origin: right; } 100% { transform: scaleX(0); opacity: 0; transform-origin: right; } }
まとめ
アニメーションのタイミング調整が難しくアバウトにやったので、本家のように綺麗にラインの表示・非表示が切り替わらないです。もっとうまいことできると思います。アニメーション設定のdurationとdelayのタイミング調整は、こだわりポイントかもしれません。同じサイトから他にもいくつかアニメーションパーツを参考にできたので良かったです。仕組みを把握するのはなかなか難しかったですが、結構楽しいのでオススメです。今回はメインの記事で時間結構費やしたのでまとめはこのくらいにします。
以上ありがとうございました。