クリックした要素をアニメーションさせる方法をメモメモ…
マウスの動作に応じてページ内の要素をアニメーションさせたい!というときの実装方法をメモしておきます。要素がボタンとかであれば CSS の疑似クラスだけで実装できるかもしれませんが、今回は普通のdiv要素を対象にするため JavaScript を使います(jQueryその他のライブラリは使いません)。ブラウザ環境によっては動作しないこともあるので注意。
まずはシンプルな例です。クリックすると「ぴょこん」と飛び跳ねます。
HTML
<div id="button">飛び跳ねさせたい要素</div>CSS
#button { display: inline-block; cursor: pointer; } #button.jump { animation: 0.4s cubic-bezier(.2,1,.2,1) 0s 1 jump; } @keyframes jump { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-40px); } }JavaScript
const button = document.getElementById("button"); button.addEventListener("mousedown", () => {button.classList.add("jump");}); button.addEventListener("animationend", () => {button.classList.remove("jump");}); button.addEventListener("animationcancel", () => {button.classList.remove("jump");});
要素がクリックされたらクラスを追加。1回だけアニメーションが再生されるようにしておきます。再生が完了(または中止)したらクラスを外して、またクリックされたら追加…を繰り返します。CSS の animation の指定が割とややこしいので、書き方をよく確認しましょう(自分も間違ってるかも…)。
さらにもう少し手を加えるとこんな感じになります。
CSS
#button { display: inline-block; cursor: pointer; } #button.wobble { animation: 0.1s ease-in 0s infinite wobble; } @keyframes wobble { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(2px); } } #button.jump { animation: 0.7s ease-in 0s 1 jump; } @keyframes jump { 0% { transform: translateY(0px) rotateZ(0deg); } 10% { transform: translateY(-10px) rotateZ(-20deg); } 35% { transform: translateY(-40px) rotateZ(-20deg); } 70% { transform: translateY(0px) rotateZ(-16deg); } 85% { transform: translateY(-14px) rotateZ(-8deg); } 100% { transform: translateY(0px) rotateZ(0deg); } }JavaScript
function startJump(){ button.classList.remove("wobble"); button.classList.add("jump"); } function stopJump(event){ if(event.animationName === "jump"){ button.classList.remove("jump"); button.classList.add("wobble"); } } const button = document.getElementById("button"); button.classList.add("wobble"); button.addEventListener("mousedown", startJump); button.addEventListener("animationend", stopJump); button.addEventListener("animationcancel", stopJump);
なんだかややこしそうですが、要は「"wobble" と "jump" を切り替える」という単純なことをやっているだけです。ただしそのままだと animationend イベントが "wobble" アニメーションの再生終了時にも実行されてしまうので、stopJump() 関数内でif(event.animationName === "jump")と書いてはじいています。
上記の2つのパターンではアニメーションの再生が終了するまでクリックに反応しませんでしたが、次の例ではクリックするたびにアニメーションが最初から再生されます。
CSS
#button { display: inline-block; cursor: pointer; } #button.jump { animation: 0.4s ease-in 0s 1 jump; } @keyframes jump { 0% { transform: translateY(0px) rotateZ(0deg); } 30% { transform: translateY(-30px) rotateZ(10deg); } 35% { transform: translateY(-30px) rotateZ(-30deg); } 45% { transform: translateY(-30px) rotateZ(30deg); } 55% { transform: translateY(-30px) rotateZ(-30deg); } 65% { transform: translateY(-30px) rotateZ(30deg); } 70% { transform: translateY(-30px) rotateZ(10deg); } 100% { transform: translateY(0px) rotateZ(0deg); } }JavaScript
const button = document.getElementById("button"); button.addEventListener("mousedown", () => { button.classList.remove("jump"); void button.offsetWidth; button.classList.add("jump"); });
連打するとその都度アニメーションがリセットされます。ポイントはvoid button.offsetWidth;という部分。通常 classList.remove() と classList.add() でクラスを付け外しするだけではアニメーションは再生されません。そこで offsetWidth にアクセスすることで強制的にリフロー(レイアウトの再計算)を発生させ、アニメーションをリセットさせている、というわけです。詳しい内容は次のページが参考になります。
How To Restart a CSS Animation With JavaScript - Better Programming - Medium
https://medium.com/better-programming/how-to-restart-a-css-animation-with-javascript-and-what-is-the-dom-reflow-a86e8b6df00f
もしvoid button.offsetWidth;でうまく動作しない場合はbutton.offsetWidth = button.offsetWidth;という書き方にしてみると機能するかもしれません。それでもダメなら「まったく同じ要素を新しく複製して古いほうを削除する」という方法もあります。
Restart CSS Animation | CSS-Tricks
https://css-tricks.com/restart-css-animation/
ただ、正直どちらの方法にしてもちょっと裏技的というか…あまり綺麗な方法じゃない気もします。特にリフローは場合によってはパフォーマンスに影響が出る可能性もありますし…。もっとシンプルな方法があれば知りたいです。
0 件のコメント:
コメントを投稿