ニートに学ぶCSS Animation演出講座 2時間目
あいさつ
ハロー、yuki540だよ!ピロリン
みんな、前回の記事は見てくれたかな?
見てない人は、ぜひ見て実践してみてね!
さてと、じゃあ今回は何をするか説明するね。
今回作るのは、こちら!!!
「ニートに学ぶCSS Animation演出講座 2時間目」はこれを解説します。
— yuki540 (@eriri_jp) 2018年3月2日
長めのアニメーション & 画面を広く使った演出の方法を学べたらなと思います。 pic.twitter.com/oYcf24M9JY
前回より長めのアニメーションだね。
あと、画面を広く使っているところと画像を一切使ってないところにも注目してほしいな。
これは、yuki540.com_version4.0.0の「共依存」でも使った演出だよ!
実は、一部「東京喰種:re テレビcm」のアニメーションを参考にしてるよ!
自分でアニメーション演出を考えるときは、自分の好きな動画なんかから動かし方のヒントをもらうのがおすすめだよ!(僕の場合は、アニメopとかMADからヒントをもらってるよ!)
今回は、コードがちょっと多くなるから、しんどいかもしれないけど頑張って!
それでは、早速やっていきまーしょう!
やっていきまーしょう!
まず完成したものを見たいと思うので、完成品はこちら。(PCを想定して作っているのでPCで見てね)
見ましたね?はい、じゃあエディタを立ち上げて一緒にコードを書きましょう!
今回のアニメーションは#prologue
と#episode-1
っていう風に物語っぽい感じにパートを区切ってます。
prologue
まずは、#prologue
から作っていきましょう。
マークアップ
<main id="stage"> <section id="prologue"> <div class="word-1"> <div><p>ニ</p></div> <div><p>ー</p></div> <div><p>ト</p></div> <div><p>は</p></div> </div> <div class="word-2"> <div><p>つ</p></div> <div><p>ら</p></div> <div><p>い</p></div> </div> <div class="connect-line"> <div class="line line-1"></div> <div class="line line-2"></div> <div class="point point-1"></div> <div class="point point-2"></div> <div class="point point-3"></div> </div> </section> </main>
表示するテキストはお好きなものを!
ちょっと今回コードが多いので細かい説明は省きます...
スタイル
html, body { margin: 0; padding: 0; } p { margin: 0; } #stage { position: absolute; top: 0; left: 0; width: 100%; height: 100%; min-width: 1100px; min-height: 650px; overflow: hidden; } /** * #prologue */ #prologue { position: absolute; top: 0; left: 0; width: 200%; height: 100%; } /*** 共通: .word-1, .word-2 ***/ #prologue .word-1, #prologue .word-2 { position: absolute; top: calc(50% - 60px); height: 120px; } #prologue .word-1 div, #prologue .word-2 div { float: left; width: 120px; height: 120px; border: dashed 1px #888; border-right: none; box-sizing: border-box; } #prologue .word-1 div p, #prologue .word-2 div p { width: 100%; height: 100%; font-size: 80px; color: #777; text-align: center; line-height: 120px; opacity: 0; } #prologue .word-1 div:last-child, #prologue .word-2 div:last-child { border-right: dashed 1px #888; } #prologue .word-1:after, #prologue .word-2:after { content: ""; display: block; clear: both; } /*** .word-1 ***/ #prologue .word-1 { left: calc(25% - 240px); } /*** .word-2 ***/ #prologue .word-2 { right: 80px; } /*** .connect-line ***/ #prologue .connect-line { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } #prologue .connect-line .point { position: absolute; top: calc(50% + 90px); width: 20px; height: 20px; background-color: #666; border-radius: 50%; } #prologue .connect-line .point-1 { left: calc(25% - 250px); } #prologue .connect-line .point-2 { left: calc(25% + 230px); } #prologue .connect-line .point-3 { right: 70px; transform: scale(0); } #prologue .line { position: absolute; top: calc(50% + 99px); height: 1px; overflow: hidden; } #prologue .line:after { content: ""; display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: #666; transform: translateX(-100%); } #prologue .line-1 { width: 480px; left: calc(25% - 240px); } #prologue .line-2 { width: calc(((50% - 480px) / 2) + (50% - 80px)); right: 80px; }
flex
じゃなく、癖でfloat
使っちゃうので「float
なんて使いたくない」って方はflex
なりを使ってください。
↓ 実際にこんな風にレイアウトが組まれるようになっています。
左側
右側
注目してほしいところは
#prologue
のwidth
が200%
であること.line
に:after
(擬似要素)が設定されていること
の2点です。
アニメーション
では、アニメーションをつけていきましょう。
/*** .word-1 ***/ #prologue .word-1 div:nth-child(1) p { animation: show-word 0.6s ease-out 0.0s forwards; } #prologue .word-1 div:nth-child(2) p { animation: show-word 0.6s ease-out 0.2s forwards; } #prologue .word-1 div:nth-child(3) p { animation: show-word 0.6s ease-out 0.4s forwards; } #prologue .word-1 div:nth-child(4) p { animation: show-word 0.6s ease-out 0.6s forwards; } /*** .line-1 ***/ #prologue .line-1:after { animation: draw-line 1.2s ease 0s forwards; } /*** #prologue: ここで右側に移動する ***/ #prologue { animation: move-prologue 0.8s ease 1.2s forwards; } /*** .line-2 ***/ #prologue .line-2:after { animation: slash-line 1.6s ease 1.2s forwards; } /*** .point-3 ***/ #prologue .point-3 { animation: put-point 1s ease-out 2s forwards; } /*** .word-2 ***/ #prologue .word-2 div:nth-child(1) p { animation: show-word 0.6s ease-out 1.6s forwards; } #prologue .word-2 div:nth-child(2) p { animation: show-word 0.6s ease-out 1.8s forwards; } #prologue .word-2 div:nth-child(3) p { animation: show-word 0.6s ease-out 2.0s forwards; } /*** .word-2: ここで次のパートに繋ぐための回転 ***/ #prologue .word-2 { animation: rotate-word-2 0.4s ease 2.6s forwards; } /********************************************************************************* keyframes **********************************************************************************/ @keyframes show-word { 0% { transform: scale(0.4); opacity: 0; } 70% { transform: scale(1.05); opacity: 1; } 100% { transform: scale(1); opacity: 1; } } @keyframes draw-line { 0% { transform: translateX(-100%); } 100% { transform: translateX(0%); } } @keyframes slash-line { 0% { transform: translateX(-100%); } 50% { transform: translateX(0%); } 100% { transform: translateX(100%); } } @keyframes move-prologue { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } } @keyframes put-point { 0% { transform: scale(0); } 70% { transform: scale(2); } 100% { transform: scale(0); } } @keyframes rotate-word-2 { 0% { transform: rotate(0deg); opacity: 1; } 100% { transform: rotate(-90deg); opacity: 0; } }
はい...泥臭い書き方になってきましたね...
そうなんです。css animation自体が今回のような長めのアニメーションを作るための機能でないため、どうしてもコードが煩雑になってしまいます。
僕はこの煩雑なコーディングを「丹精込めた手打ちkeyframes」と呼んでいます。
で、解説しますと、
まず、.word-1
をshow-word
で0.2秒間隔を開けながら、アニメーションします。
それと同時に.word-1
の下にある.line-1
をdraw-line
で0.8秒かけながらアニメーションします。
ここで.line-1
で線を引くのにwidth
を変更せずに.line-1:after
をtranslateX
で右側に移動させることで線を引いているように見せているのは描画コストを下げるためです。
次に#prologue
自体をmove-prologue
で右側に移動させます。
これも同様にtranslateX
を使ってできるだけ描画コストを下げます。
このようなダイナミックな画面移動が画面を広く使ったアニメーション演出をより盛り上げてくれます。
#prologue
が移動すると同時に.line-2
をslash-line
でアニメーションさせます。
draw-line
と違い、translateX(-100%)
~ translateX(100%)
で通り過ぎています。
通り過ぎることで、.point-3
のput-point
アニメーションに吸い込まれているような表現になります。
次は、word-1
と同様に.word-2
をshow-word
で0.2秒間隔を開けながらアニメーションさせます。
あとは、.word-2
をrotate-word-2
で-90度回転させれば、prologue
のパートは完成です。
episode-1
次は、#episode-1
をやっていきましょう。
マークアップ
<main id="stage"> <section id="prologue"><!-- 省略 --></section> <!-- ここから --> <section id="episode-1"> <div class="message-panel"> <div class="message"> <p class="char">ミ</p> <p class="char">ラ</p> <p class="char">イ</p> <small class="text">ハロー、ミライアカリだよ!ピロリン</small> </div> <div class="message"> <p class="char">ア</p> <p class="char">カ</p> <p class="char">リ</p> <p class="char">は</p> <small class="text">CSS Animation演出講座、みんなも受けてね!</small> </div> <div class="message"> <p class="char">か</p> <p class="char">わ</p> <p class="char">い</p> <p class="char">い</p> <small class="text">それでは、やっていきまーしょう!</small> </div> </div> </section> <!-- ここまで --> </main>
上記のものを追加してください。(これもテキストはお好きなものを)
スタイル
/** * episode-1 */ #episode-1 { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } #episode-1 .message-panel { position: absolute; top: calc(50% - 180px); right: 80px; width: 360px; height: 360px; transform: rotate(90deg); } #episode-1 .message-panel .message { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } #episode-1 .message-panel .message .char { float: left; width: 170px; height: 170px; font-size: 150px; color: #333; text-align: center; line-height: 170px; opacity: 0; } #episode-1 .message-panel .message .char:nth-child(1), #episode-1 .message-panel .message .char:nth-child(2) { margin-bottom: 20px; } #episode-1 .message-panel .message .char:nth-child(2n-1) { margin-left: 20px; } #episode-1 .message-panel .message .text { position: absolute; top: 165px; left: 40px; width: 320px; height: 30px; display: block; font-size: 14px; color: #555; line-height: 30px; opacity: 0; } #episode-1 .message-panel .message:after { content: ""; display: block; position: absolute; top: 0; left: 0; width: 15px; height: 100%; background-color: #5D97BD; opacity: 0; }
レイアウトは以下のように組まれます。
特に説明することがないので、スタイルの説明は省きます。
アニメーション
/*** .message-panel ***/ #episode-1 .message-panel { animation: rotate-message-panel 0.7s ease 2.6s forwards, move-left-message-panel 0.5s ease 3.6s forwards, move-right-message-panel 0.5s ease 4.7s forwards; } /*** .message:nth-child(1):after ***/ #episode-1 .message-panel .message:nth-child(1):after { animation: show-bar 0.5s ease 2.8s forwards; } /*** .char ***/ #episode-1 .message-panel .message:nth-child(1) .char:nth-child(1) { animation: show-char 0.35s ease 2.8s forwards; } #episode-1 .message-panel .message:nth-child(1) .char:nth-child(2) { animation: show-char 0.35s ease 2.9s forwards; } #episode-1 .message-panel .message:nth-child(1) .char:nth-child(3) { animation: show-char 0.35s ease 3.0s forwards; } /*** .text ***/ #episode-1 .message-panel .message:nth-child(1) .text { animation: show-text 0.5s ease 3.1s forwards; } /*** .message:nth-child(1) ***/ #episode-1 .message:nth-child(1) { animation: fadeout 0.5s ease 3.6s forwards; } /*** .message:nth-child(2):after ***/ #episode-1 .message-panel .message:nth-child(2):after { animation: show-bar 0.5s ease 3.8s forwards; } /*** .char ***/ #episode-1 .message-panel .message:nth-child(2) .char:nth-child(1) { animation: show-char 0.35s ease 3.8s forwards; } #episode-1 .message-panel .message:nth-child(2) .char:nth-child(2) { animation: show-char 0.35s ease 3.9s forwards; } #episode-1 .message-panel .message:nth-child(2) .char:nth-child(3) { animation: show-char 0.35s ease 4.0s forwards; } #episode-1 .message-panel .message:nth-child(2) .char:nth-child(4) { animation: show-char 0.35s ease 4.1s forwards; } /*** .text ***/ #episode-1 .message-panel .message:nth-child(2) .text { animation: show-text 0.5s ease 4.2s forwards; } /*** .message:nth-child(2) ***/ #episode-1 .message:nth-child(2) { animation: fadeout 0.5s ease 4.7s forwards; } /*** .message:nth-child(3):after ***/ #episode-1 .message-panel .message:nth-child(3):after { animation: show-bar 0.5s ease 4.9s forwards; } /*** .char ***/ #episode-1 .message-panel .message:nth-child(3) .char:nth-child(1) { animation: show-char 0.35s ease 4.9s forwards; } #episode-1 .message-panel .message:nth-child(3) .char:nth-child(2) { animation: show-char 0.35s ease 5.0s forwards; } #episode-1 .message-panel .message:nth-child(3) .char:nth-child(3) { animation: show-char 0.35s ease 5.1s forwards; } #episode-1 .message-panel .message:nth-child(3) .char:nth-child(4) { animation: show-char 0.35s ease 5.2s forwards; } /*** .text ***/ #episode-1 .message-panel .message:nth-child(3) .text { animation: show-text 0.5s ease 5.3s forwards; } /******************************************************************************** keyframes *********************************************************************************/ @keyframes fadeout { 0% { opacity: 1; } 100% { opacity: 0; } } @keyframes fadein { 0% { opacity: 0; } 100% { opacity: 1; } } @keyframes rotate-message-panel { 0% { transform: rotate(90deg); } 60% { transform: rotate(-5deg); } 100% { transform: rotate(0deg); } } @keyframes show-char { 0% { transform: translateX(100px); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } @keyframes show-text { 0% { transform: translateX(-100px); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } @keyframes show-bar { 0% { width: 300px; opacity: 0; } 100% { width: 15px; opacity: 1; } } @keyframes move-left-message-panel { 0% { right: 80px; } 100% { right: calc(100% - 450px); } } @keyframes move-right-message-panel { 0% { right: calc(100% - 450px); } 100% { right: 80px; } }
さっきから意味不明なキーフレーム名ですが、単に僕の英語力と英単語のバリエーションがないだけなので、自分でお好きなキーフレーム名を設定していただいて大丈夫です...
で、解説しますと、
まず、.message-panel
をrotate-message-panel
で前のパートの回転を引き継いでいるように見せます。
で、.message-panel
に複数のキーフレームをカンマ区切りで指定していますね。
実は、animationプロパティは複数のキーフレームを適用することができます。
これを使うことでアニメーションを繋げていくこともできますし、複数のキーフレームを同時に適用することもできます。
回転しながら、.message:after
をshow-bar
でアニメーションさせ、.char
をshow-char
で0.1秒間隔を空けながらアニメーションさせます。
その次に.text
をshow-text
で0.5秒かけてアニメーションします。
↓ 言葉で説明するのが難しいですが、こんな感じになります。
細かい動きを確認用 pic.twitter.com/otrqXypJwz
— yuki540 (@eriri_jp) 2018年3月4日
回転しすぎて、バウンドしているようにみせることで、より気持ちのいいアニメーションになります。
後は、.message-panel
をmove-left-message-panel
で左側に移動させながら、.message:nth-child(1)
をfadeout
で非表示して、.message:nth-child(2)
側にアニメーションを引き継がせるだけです。
さっきと同じ書き方なので説明は省きます。
違いは、.message-panel
が移動しているだけです。
終わり。
どうでしょうか?動きましたか?
コードが多めなのに説明が雑ですみません...
完成したコードはこちらにあるので、うまくいかない方はご覧ください。
おわりに
今回も説明が下手 & 説明が雑で読みづらかったと思いますが、最後までみてくださりありがとうございました。
画面を広く使うことでアニメーションに迫力が出ることと、画像を使わなくても楽しい表現ができることがちょっとでも伝わってくれたなら幸いです。
これからも毎週日曜更新で続けていきますので、よかったらまたみてください。
じゃーねー!