こんにちは。KOUKIです。
本記事は、Udemyの「50 Projects In 50 Days – HTML, CSS & JavaScript」で学習したことを載せています。
<目次>
実装するもの
今回は、カウントダウンアプリをCSSでスタイリングしたいと思います。
demoは「こちら」で確認できます。
ワークスペース
必要なファイルは、以下の通りです。
1 2 3 4 5 6 |
$ tree . ├── index.html ├── script.js └── style.css |
JavaScript版
HTML & JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="style.css" /> <title>Animated Countdown</title> </head> <body> <div class="counter"> <div class="nums"> <span class="in">3</span> <span>2</span> <span>1</span> <span>0</span> </div> <h4>Get Ready</h4> </div> <div class="final"> <h1>GO</h1> <button id="replay">Replay</button> </div> <script src="script.js"></script> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
// 要素の取得 const nums = document.querySelectorAll('.nums span') const counter = document.querySelector('.counter') const finalMessage = document.querySelector('.final') const replay = document.querySelector('#replay') // アニメーション実行 runAnimation() function runAnimation() { // span要素の数だけ実行 nums.forEach((num, idx) => { // 配列数を取得 const nextToLast = nums.length - 1 // animationendイベントの登録 num.addEventListener('animationend', (e) => { // goInが終了し、かつ要素が最後ではない場合 if(e.animationName === 'goIn' && idx !== nextToLast) { // classの付け替え num.classList.remove('in') num.classList.add('out') } else if( // goOutが終了し、かつ、指定要素の"次の要素"が存在している場合 e.animationName === 'goOut' && num.nextElementSibling) { // classの付け替え num.nextElementSibling.classList.add('in') } else { // カウントダウンが完了した場合 // classの付け替え counter.classList.add('hide') finalMessage.classList.add('show') } }) }) } function resetDOM() { // classを除去 counter.classList.remove('hide') finalMessage.classList.remove('show') nums.forEach((num) => { // classを除去 num.classList.value = '' }) // <span class>3</span>にinをつける nums[0].classList.add('in') } // Replyボタンのクリックイベント replay.addEventListener('click', () => { resetDOM() runAnimation() }) |

スタイリング
CSSでスタイリングします。項目に出てくるbodyやh4は、HTML要素です。
全体の設定
1 2 3 4 5 6 7 |
/* フォント */ @import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"); * { /* ボックスの大きさを算出する */ box-sizing: border-box; } |
bodyの設定
1 2 3 4 5 6 |
body { font-family: "Roboto", sans-serif; margin: 0; height: 100vh; overflow: hidden; } |

h4の設定
1 2 3 4 5 6 |
h4 { font-size: 20px; margin: 5px; /* テキストを大文字 */ text-transform: uppercase; } |

counterの設定
1 2 3 4 5 6 7 8 9 10 11 12 |
.counter { /* アイテム位置固定 */ position: fixed; /* 要素を真ん中寄せにする */ top: 50%; left: 50%; transform: translate(-50%, -50%); /* テキストを真ん中寄せ */ text-align: center; } |

hideの設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.counter.hide { transform: translate(-50%, -50%) scale(0); /* hideアニメーションの設定 */ animation: hide 0.2s ease-out; } @keyframes hide { 0% { transform: translate(-50%, -50%) scale(1); } 100% { transform: translate(-50%, -50%) scale(0); } } |

finalの設定
1 2 3 4 5 6 |
.final { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0); } |

final.showの設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
.final.show { transform: translate(-50%, -50%) scale(1); /* アニメーション設定 */ animation: show 0.2s ease-out; } @keyframes show { 0% { transform: translate(-50%, -50%) scale(0); } 30% { transform: translate(-50%, -50%) scale(1.4); } 100% { transform: translate(-50%, -50%) scale(1); } } |

numsの設定
1 2 3 4 5 6 7 8 9 |
.nums { color: #3498db; font-size: 50px; /* アイテム位置の起点 */ position: relative; overflow: hidden; width: 250px; height: 50px; } |

nums spanの設定
1 2 3 4 5 6 7 8 9 10 |
.nums span { /* relativeから見た絶対値 */ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(120deg); /* 要素の変形transformにおける原点を設定 */ /* x-offset | y-offset */ transform-origin: bottom center; } |

In/Outの設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
.nums span.in { transform: translate(-50%, -50%) rotate(0deg); animation: goIn 0.5s ease-in-out; } @keyframes goIn { 0% { transform: translate(-50%, -50%) rotate(120deg); } 30% { transform: translate(-50%, -50%) rotate(-20deg); } 60% { transform: translate(-50%, -50%) rotate(10deg); } 100% { transform: translate(-50%, -50%) rotate(0deg); } } .nums span.out { animation: goOut 0.5s ease-in-out; } @keyframes goOut { 0% { transform: translate(-50%, -50%) rotate(0deg); } 60% { transform: translate(-50%, -50%) rotate(20deg); } 100% { transform: translate(-50%, -50%) rotate(-120deg); } } |


これで、完成です。
おわりに
アニメーションで要素を浮かび上がらせている処理は、かなり勉強になりますね^^
動きのあるアプリケーションの実装は、やはりワクワクします。
JavaScriptの知識も必要になりますが、ぜひ一度、実装してみてください。
それでは、また!
CSSまとめ
CSSソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
/* フォント */ @import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"); * { /* ボックスの大きさを算出する */ box-sizing: border-box; } body { font-family: "Roboto", sans-serif; margin: 0; height: 100vh; overflow: hidden; } h4 { font-size: 20px; margin: 5px; /* テキストを大文字 */ text-transform: uppercase; } .counter { /* アイテム位置固定 */ position: fixed; /* 要素を真ん中寄せにする */ top: 50%; left: 50%; transform: translate(-50%, -50%); /* テキストを真ん中寄せ */ text-align: center; } .counter.hide { transform: translate(-50%, -50%) scale(0); /* hideアニメーションの設定 */ animation: hide 0.2s ease-out; } @keyframes hide { 0% { transform: translate(-50%, -50%) scale(1); } 100% { transform: translate(-50%, -50%) scale(0); } } .final { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0); } .final.show { transform: translate(-50%, -50%) scale(1); /* アニメーション設定 */ animation: show 0.2s ease-out; } @keyframes show { 0% { transform: translate(-50%, -50%) scale(0); } 30% { transform: translate(-50%, -50%) scale(1.4); } 100% { transform: translate(-50%, -50%) scale(1); } } .nums { color: #3498db; font-size: 50px; /* アイテム位置の起点 */ position: relative; overflow: hidden; width: 250px; height: 50px; } .nums span { /* relativeから見た絶対値 */ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(120deg); /* 要素の変形transformにおける原点を設定 */ /* x-offset | y-offset */ transform-origin: bottom center; } .nums span.in { transform: translate(-50%, -50%) rotate(0deg); animation: goIn 0.5s ease-in-out; } @keyframes goIn { 0% { transform: translate(-50%, -50%) rotate(120deg); } 30% { transform: translate(-50%, -50%) rotate(-20deg); } 60% { transform: translate(-50%, -50%) rotate(10deg); } 100% { transform: translate(-50%, -50%) rotate(0deg); } } .nums span.out { animation: goOut 0.5s ease-in-out; } @keyframes goOut { 0% { transform: translate(-50%, -50%) rotate(0deg); } 60% { transform: translate(-50%, -50%) rotate(20deg); } 100% { transform: translate(-50%, -50%) rotate(-120deg); } } |
コメントを残す
コメントを投稿するにはログインしてください。