これまでは要素を目的の場所へ配置するだけでしたが、ここからは要素を動かし、よりリッチな見た目を実装する方法について解説します。
最近のwebサイトでは3Dを使用し、ただ情報を見せるだけでなく、鑑賞するコンテンツとして使用する事も増えてきました。
3D技術を使用すればweb上でバーチャル空間や、モデリング、さらにはその技術を発展させ、メタバースなどにも応用可能なわくわくする世界です。
ここではその一歩となるwebサイト上でのアニメーションの表現で使用する技術を学習していきますが、小さなアニメーションをサイトに施すだけでも一般的なサイトとは一味違ったサイトを制作する事が可能になります。
Transform
cssのtransformプロパティを使用する事で要素を移動・変形させる事が可能です。
transformはこれまでの章でも出てきたかと思います。
例えば、position: fiexdとtransformの相性についてなど…
さりげなく使用していましたが、transformをマスターすると表現の幅を大きく広げる事が可能です。
ただ、transformは移動や変形を行いますので、少し理解する事が難しいです。
ですので、この章でしっかり学び、ぜひマスターし、思い通りのデザインを再現できるようになってください。
要素の移動
translateを使用する事で要素をX軸Y軸方向に移動する事が可能です。
以下のように記載します。
transform: translate(X軸, Y軸);
translateの値にX軸方向に何px動かしたいか、Y軸方向に何px動かしたいかを記載する事で要素を元あった位置からそれぞれの方向に動かす事が可能です。
これはmarginなどのような移動ではなく、positionのような移動になります。
その要素のフロー上の位置は変化しないという事です。
margin-leftで要素を右に移動させた場合、要素はフロー上、右に移動する事になりますので、後に続く要素も同じく右に押しやられます。
ですが、transformを使用すると、positionで移動させたように、フロー上では変換はなく、そこから要素が右に移動します。ですので、周りの要素への影響はありません。
別々の指定
上ではX軸とY軸を一緒に指定していましたが、個別で指定する事も可能です。
transform: translateX(10px); transform: translateY(20px); // こちらと同じです transform: translate(10px, 20px);
%での指定
先ほどはtransformの値をpxで指定しました。pxで指定した場合、その要素はフロー上から絶対的なpxという単位で移動しましたが、%を指定すると、相対的な指定となります。
positionの場合、%で相対的な位置指定をするとrelativeを持っている親要素に対しての相対的な値がセットされましたが、fransformの場合は自分自身の大きさを元に値を決めます。
以下は実際の違いを表したデモです。
See the Pen Untitled by tora (@-tora-) on CodePen.
pxと%を一緒に定義する
calcを使用すればpxと%を一緒に使用しより汎用的に位置を決める事が可能です。
transform: translate(calc(50% + 10px), 0px)
このようにする事で半分移動したのち、10pxのオフセットを取る事ができます。
要素の回転
rotateを使用する事で要素を回転する事が可能です。
要素を回転させる時の単位はdegを使用します。
transform: rotate(45deg)
プラスの値をセットすると時計周りに、マイナスの値をセットすると半時計周りに回転します。
要素の拡大・縮小
scaleを使用する事で要素を拡大縮小する事ができます。
値をセットする際に単位は必要ありません。例えば以下のように2をセットすると要素は2倍の値となります。
transform: scale(2);
See the Pen Untitled by tora (@-tora-) on CodePen.
これを見ると一見、横幅や高さを2倍にしたように思うかもしれませんが、異なります。
ここにテキストを置いてみましょう。
See the Pen Untitled by tora (@-tora-) on CodePen.
すると上のように、テキストも拡大されました。
横幅や高さを増やすなら中のテキストは大きくなる事ありませんが、scaleで拡大すると中のテキストの一緒に大きくなります。これは一枚の画像を拡大しているかのような動きです。
要素の変形・傾き
skewを使用する事で要素のに傾きを持たせ、変形させることができます。
これは装飾で使用される事があります。
skewの単位はdegを使用して角度であらわします。
skewにもX軸方向の傾きとY軸方向の傾きが存在し、skew(X軸, Y軸)このように記載します。
X軸方向への傾き
transform: skew(30deg, 0);
See the Pen Untitled by tora (@-tora-) on CodePen.
Y軸方向への傾き
transform: skew(0, 30deg);
See the Pen Untitled by tora (@-tora-) on CodePen.
transformの原点
今まで何となく移動、拡大、回転などを行っていましたが、これらの操作の原点はどこなのでしょうか。
例えば、わかりやすいものが回転ですがrotateで回転させた時デフォルトの状態では原点は要素の中心となっています。
この原点は移動させる事が可能です。
移動させる事でどのような事が起こるのでしょうか。見てみましょう。
まず原点を移動させるにはtransform-originを使用します。
transform-originの値は以下の単位を使用して設定する事が可能です。
- %
- px
- テキスト(center, top left, bottom rightなど)
例えば原点を左上にしてみます。
transform-origin: top left;
このように原点を左上にする事により、回転する軸が変わり見た目にも影響がでました。
この例ではテキストで「top left」と原点の位置を指定しましたが、pxや%で同じように指定するには以下のように行います。
// 左上 transform-origin: 0px 0%; //右上 transform-origin: top 100%; // 右下 transform-origin: 100% 100%; // 左下 transform-origin: 100% 0px; // 中央右側 transform-origin: center right;
このように複数の単位を組わせて指定する事が可能です。
操作の組わせ
今までは1つ1つ値を指定して使っていました。
これらを組み合わせて、移動させつつ、回転するというような事が可能です。
指定の方法は以下のように、単純に並べて記載すればよいです。
transform: translate(30px, 0) rotate(45deg);
こうする事で回転した状態で右に移動させる事が可能です。
See the Pen Untitled by tora (@-tora-) on CodePen.
記載する順番に注意
上ではtranslate(30px, 0) rotate(45deg)という順番で記載しましたが、この順番が入れ替わってしまうと結果も変わります。
ググってみると後に記載した方から実行させるというような説明があります。
その認識の方が正しいのかもしれませんが、直観的ではないので自分の頭の中で考える時は以下のようにイメージしましょう。
- 記載順で考え、まず、transpateでX軸方向に30px移動します
- rotateで時計回りに45°回転します。
これを逆に記載してみます。すると以下のようになってしまいます。
- 記載順で考え、まず、rotateで時計周りに45°回転します。この時注意すべ起点は、Y軸、X軸も一緒に回転している点です。
- 軸が一緒に回転していますので、ここからtranslateによってX軸に30px移動しますと、結果が変わります。
inline要素には効かない
inline要素にtransformは効きません。
inline要素は横並びになる要素です。要素を縦方向に動かすと横並びのテキストがガタガタになってしまいます。
ですのでinlineではtransformを使用することはできません。
Transition
transitionを使用する事で要素の変化を滑らかにし、アニメーションを制作します。
以下のデモで、要素にマウスホバーをしてみてください。
See the Pen Untitled by tora (@-tora-) on CodePen.
transitionを使用するための構成要素は以下になります。
transition-delay
-> トランジション効果が始まるまでの待ち時間transition-duration
-> アニメーションが完了するまでの時間transition-property
-> トランジション効果を適応するプロパティ名transition-timing-function
-> トランジションの効果
上の4つの値をセットしてアニメーションをコントロールします。
例えば以下のように、ホバーから0.5秒後に1秒かけてx軸方向に30px動かしたい時はこのようにcssを記載します。
.box { transition-delay: .5s; transition-duration: 1s; transition-property: transform; } .box:hover { transform: translate(30px, 0); }
transition-delayでトランジションの開始を0.5秒遅らせます(単位はsです)
transition-durationでトランジションが完了する時間を1秒にセットします。
どのプロパティにこのトランジション効果を適応させたいかをtransition-propertyから指定します。
今回はtransformでx軸方向に30px動かしています。transformにトランジションを適応させたいので、transition-propertyにtransformをセットします。
transition-timing-function
transition-timing-functionはアニメーション中の要素の動きを制御します。
transition-timing-functionの値は複数あり、自分で制作する事も可能です。
まずはデフォルトで用意されている値から見ていきましょう。
- ease デフォルト値
- ease-in
- ease-out
- ease-in-out
- linear
- step-start
- step-end
言葉で説明するより実際の動きを見る方が理解がしやすいので動きを載せます。
ease
transition-timing-functionの値をセットしない場合、easeがデフォルトの値としてセットされ、こちらの動きとなります。
transition-timing-function: ease;
ease-in
transition-timing-function: ease-in;
ease-out
transition-timing-function: ease-out;
ease-in-out
transition-timing-function: ease-in-out;
linear
transition-timing-function: linear;
step-start
transition-timing-function: step-start;
トランジションをかけていないときと同じで、瞬時に変化します。
step-end
transition-timing-function: step-end;
トランジションの開始時に変化せず、終了時に変化が完了した状態になります。
transition-timing-functionの値をカスタマイズする
これまでの紹介ではtransition-timing-functionで使用出来る値はデフォルトで用意されているテキストでの指定でした。
そしてその指定した値によって、アニメーションを変化させる事が可能でしたが、この値を変化させ、オリジナルのアニメーションを適応する事が可能です。
オリジナルの動きを作るためにはcubic-bezier関数を利用し、以下のようなベジェ曲線を使用して制作します。
cubic-bezierは以下のように4つ値から構成されます。
cubic-bezier(p1, p2, p3, p4);
ですが、実装したいアニメーションを数値に落とし込む事は難しいですので以下のような制作ツールを使用しましょう。
マウス操作で簡単にベジェ曲線と実際のアニメーションを確認する事ができます。
その他にも、以下のように、よく使用される気持ちのいいアニメーションを一覧にしたチートシートがあります。
transition-delayの活用
transition-delayはトランジション効果を遅らせる事ができるものですが、どのような場面で活躍するのでしょうか。
以下の動画を見てください。
メニューボタンがあり、そのメニューボタンをホバーするとメニューが展開します。
ですが、メニューまでに距離があるので、メニューを選択するためには一度メニューボタンからホバーを外す必要が出てきます。
その瞬間、ホバーアクションが外れてしまうのでメニューは閉じてしまいます。
この問題を解決するためにtransition-delayを使用します。
transition-delayを使用してトランジションを遅延させます。
すると、ユーザーがボタンの外にマウスを移動させても何も起こりません。
その後、ユーザーがメニューへホバーする事でホバーアクションが起こり、状態遷移は行われず、常にメニューが開いているように見えます。
HTML
<div class="menu-area"> <button class="menu-button"> <span></span> <span></span> <span></span> </button> <div class="menu"> <ul class="menu-list"> <li class="menu-list-item">menu 1</li> <li class="menu-list-item">menu 2</li> <li class="menu-list-item">menu 3</li> <li class="menu-list-item">menu 4</li> </ul> </div> </div>
CSS
.menu-area { position: relative; } .menu-button { border: solid 1px #000; border-radius: 50%; width: 50px; height: 50px; background-color: #fff; display: flex; justify-content: center; align-items: center; gap: 6px; } .menu-button span { border-radius: 50%; width: 4px; height: 4px; background-color: #000; } .menu-button:hover + .menu { visibility: visible; opacity: 1; top: 70px; } .menu { visibility: hidden; opacity: 0; position: absolute; top: 50px; left: 50px; border: solid 1px #000; padding: 18px; transition: visibility .1s ease, opacity .1s ease, top .1s ease; transition-delay: .2s; } .menu:hover { visibility: visible; opacity: 1; top: 70px; } .menu-list { padding: 0; list-style: none; margin: 0; } .menu-list-item { }
チャタリングの対応
チャタリングとはスイッチをオンにする時に短時間にオンとオフを高速に繰り返す現象の事を言います。
transformとtransitionを使用していると、これがcssでも起こり、要素が高速で同じ事を繰り返す事があります。
以下のデモを実際に触ってみてください。
ページのTOPに戻るボタンを用意しました。
そして、このボタンはホバーをすると、上方向に滑らかにアニメーションし、移動します。
ホバー時にtransformにより、上方向に動かし、 transitionにより、その動きを滑らかにしています。
このような実装をしたとき、ボタンの下ギリギリの箇所にマウスを置いてみてください。
チャタリングが起こります。
See the Pen Untitled by tora (@-tora-) on CodePen.
これは以下のようなプロセスで起こります。
- マウスホバーにより、ホバーが有効になります。
- ホバーにより、ボタンが上方向に動きます。
- ボタンが上方向に移動した事により、ホバーが解除されます。
- ホバー解除により、ボタンが元の位置に戻ります。
1 ~ 4を繰り返します。
このチャタリングを解決するためにはホバーアクションと実際に動く要素を分離します。
See the Pen Untitled by tora (@-tora-) on CodePen.
ボタンに親要素を追加し、その親要素にホバーアクションをつけます。
子要素を選択するセレクターを使用し、子要素になったトップへのボタンにtransform処理を適応させます。
そうする事で、親である要素は移動しないので、ホバーがOFFになる事もありませんのでチャタリングを解決できるというわけです。
キーフレームアニメーション
これまではtransitionを使用してアニメーションを実装しました。
ですが、transitionでは細かいアニメーションを再現する事ができません。
細かいアニメーションを再現するためにはanimationを使用します。
アニメーションの具体的な動きは@keyframesを使って指定し、制作したアニメションキーフレームをanimation-nameにセットする事で実装できます。
See the Pen Untitled by tora (@-tora-) on CodePen.
@keyframesを使用してアニメーションを制作し、名前をslideInAnimationとしました。
そのslideInAnimationをanimation-nameにセットする事で@keyframesで制作したアニメーションが有効になります。
アニメーションの作り方
アニメーションは以下のような形式で制作します。
○○%で変化のタイミングを示し、{}の中に命令を記載します。
%{}の部分はいくつでもセットする事ができ、以下のようにすることも可能です。
0% { transform: translate(0, 20px); opacity: 0; } 50% { transform: translate(0, 10px) rotate(45deg); opacity: 0.5; } 100% { transform: translate(0, 0px); opacity: 1; }
これで50%の位置で要素が回転するようになります。
そして、アニメーションにはtransitionのように実行のタイミングや、アニメーションの長さなどを指定する事が可能です。
animation-delay
animation-delayではアニメーションをいつ開始するかを指定する事ができます。
単位はsで以下のように記載します。
animation-delay: 0.3s;
これでアニメーションが0.3秒後に実行させるようになります。
animation-direction
animation-directionはアニメーション再生の向きを順方向、逆方向、前後反転のいずれにするかを設定します。
値は文字列で以下のように記載します。
animation-direction: reverse;
- normal:通常向きでの再生で動きを繰り返します:デフォルト
- reverse:逆方向の再生で動きを繰り返します
- alternate:アニメーションを往復運動させます(初めは通常の向きで再生)
- alternate-reverse:アニメーションを往復運動させます(初めは逆の向きで再生)
animation-duration
animation-durationはアニメーションが完了する時間を指定します。
単位はsで以下のように記載します。
animation-duration: 3s;
これで3秒かけてアニメーションが実行されます。
animation-fill-mode
animation-fill-modeはCSS アニメーションの実行の前後にどう対象にスタイルを適用するかを設定します。
値は文字列で、以下のように記載します。
animation-fill-mode: none;
- none:指定なし:デフォルト
- forwards:実行後のアニメーションの値を保持します
- backwards:アニメーションの初期状態に戻ります
- both:backwardsとforwardsの両方の状態を適用します
アニメーションを実装していると、以下のような現象が起こる事がよくあります。
See the Pen Untitled by tora (@-tora-) on CodePen.
現象が確認できなかった場合は、右下にあるRerunボタンをクリックしてもう一度アニメーションを再生してください。
徐々に透明にし、フェードアウトするアニメーションですが、アニメーションが終了すると透明ではなくなってしましまい、要素が完全に見えてしまいます。
この問題を解決するためにanimation-fill-modeを使用します。
そもそもこのような現象は以下の事から起こります。
アニメーション開始と同時にopacity(不透明度)が1から0に滑らかに移行します。
ちなみに、曲線になっていますが、この曲線をベジェ曲線といい。
どのような曲線を描きながら効果が遷移するのかを表します。
transformではtransition-timing-function: ease;というように表し、animationではanimation-timing-function: ease;というように表します。
アニメーションが終了すると、デフォルトだと要素の状態は元に戻り、opacityは1になります。
ですので要素が残ったままになるというわけです。
これを以下のように終了した状態を保持する事が出来るようにするのがanimation-fill-mode: forwards;です。
forwardsはアニメーションの終わりの値を保持しまたが、backwardsを使用する事で逆に始まりの値を保持する事も可能です。
例えば以下のような実装をしたい場合に使えます。
初めは要素を画面外に隠し、フェードインで画面内に表示するアニメーションです。
ですが、アニメーションの開始時にすでに要素が見えてしまっています。
これは以下のようにアニメーションが当たっていない初期値が見える状態になっているからです。
これにbackwardsを使用することでアニメーションの初期値を保持する事が可能になります。
アニメーションの開始と終わりの値どちらも保持するためにはbothを使用します。
animation-iteration-count
animation-iteration-countはアニメーションが再生させる回数を指定します。
値は数字とテキストです。
- infinite:無限に再生を繰り返す
- 数値:数値の数だけ繰り返し
animation-play-state
animation-play-stateを使用する事でアニメーションをストップ、スタートさせることができます。
値はテキストで以下のように記載します。
animation-play-state: paused;
- paused:停止
- running:スタート
停止したアニメーションを再開すると、アニメーションの流れの最初からではなく、停止した位置からアニメーションが始まります。
Java Scriptから制御する事でアニメーションを停止したり開始したりします。
animation-timing-function
animation-timing-functionを使用する事でアニメーションの中間の動きを制御できます。
これは、 transitionのtransition-timing-functionと同じものになります。
セットできる値もtransition-timing-functionと同じです。詳しくは transition-timing-functionの章をご覧ください。
アニメーションの参考になるサイト
コードをコピペするだけで気持ちのいいアニメーションを実装する事が出来るサイトです。
様々なデザインのアニメーションがまとめられています。
transitionとanimationの使い分け
どのような場合に@keyframes使用し、どのような場合にtransitionを
使用するのか、疑問に思われるかもしれません。
その場合は、@keyframesはtransitionの上位互換と考え、@keyframesにしかできない事なのかどうかで判断します。
@keyframesにしかできない事は以下の3つになります。
- ループアニメーション
- マルチステップアニメーション
- ポーズアニメーション
このようなことは、本当にやろうと思えば、JSからもできるのです。しかし、通常は@keyframesを使う方がシンプルです。
ページのロード時やコンポーネントのマウント時に即座にアニメーションを実行する必要がある場合、@keyframesを使用するのが最も簡単です。
一方、アプリケーションの状態やユーザーの操作によってCSSが変化する場合は、transitionを使用します。値間の遷移が激しい場合に、それを滑らかにするために使うのです。
どちらのツールも用途が微妙に異なるので、どちらを使うか勘を働かせるには、ある程度の練習が必要です。