「アニメーションは動作するけどtransitionだけがうまく動作しない」
「@keyframesで作ったときとJavaScriptで作ったときとでアニメーションが違う時がある」
「最近追加された@starting-styleというCSSの使い方がよくわかっていない」
本日はそんな方に向けてアニメーションにおけるトラブルの回避方法をご紹介します。
アニメーションはウェブサイトやアプリケーションのユーザーエクスペリエンスを向上させるために重要です。
しかし、時折トランジションが思った通りに機能しないという問題に直面することがありますよね。
JSとCSSを使用してアニメーションを実装する際に、なぜトランジションが効かない問題が生じるのか、そしてその解決策について探求していきます。
またCSSに新しく追加された「@starting-style」というキーワードで解決できる場合があるので、「@starting-style」の意味と使い方も解説していきます。
具体的なシナリオに焦点を当てスムーズなアニメーションの実現に向けたヒントになるはずですので最後までご覧ください。
動画でも解説しているので必要な方は以下よりどうぞ。
displayプロパティとtransitionプロパティは相性が悪い
例えば以下のようなコードがあった場合にアニメーションがうまく動作しません。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./style.css" />
<script src="./script.js" defer></script>
</head>
<body>
<div class="container">
<article>
<h1>タイトル</h1>
<p>テキストです。テキストです。テキストです。</p>
<button class="btn">続きを見る</button>
<div class="remain">
残りのテキストです。残りのテキストです。残りのテキストです。残りのテキストです。残りのテキストです。残りのテキストです。残りのテキストです。
</div>
</article>
</div>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
transition: opacity 2s;
padding: 32px;
}
.remain {
display: none;
opacity: 0;
transition: opacity 2s;
}
.remain.show {
display: block;
opacity: 1;
}
const btn = document.querySelector(".btn");
const remain = document.querySelector(".remain");
btn.addEventListener("click", () => {
remain.classList.add("show");
});
ボタンをクリックするとremainというclassが付いた要素が非表示から表示に切り替わるものです。
CSSとJSの基本がわかっていれば難しくないものに見えます。
このように表示に切り替えることはうまくいっていますが、CSSでtransitionとopacityを設定して少しフワッとした形を期待していた部分が実現できていません。
原因としてはdisplay: none;として一度非表示にしたものに指定してあるopacityに対してtransitionを設定しても、存在していないものを監視することができないためです。
こちらを解決する方法はいろいろありますが今回はCSSのstarting-styleという機能を使用してみます。
CSSのstarting-styleの使い方
CSSではstarting-styleという機能が新しく追加されました。
こちらは名前の通り「最初のスタイル」を設定することができます。
例えば以下のようにcontainerというclass名の要素に使うことができてアニメーションを手軽に実装することができるようになりました。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
/* ここを追加 */
@starting-style {
opacity: 0;
}
transition: opacity 2s;
/* ここを追加 */
opacity: 1;
padding: 32px;
}
.remain {
display: none;
opacity: 0;
transition: opacity 2s;
}
.remain.show {
display: block;
opacity: 1;
}
opacityを0から1に切り替えることをリロード時に実行できているので、画面を読み込むとフワッと表示されました。
keyframesを使ったアニメーションを作ったことがある方は理解しやすいと思いますが、進捗率の0%がstartiing-styleに置き換わったようなものです。
つまり0%と100%のみのシンプルなkeyframesであれば、keyframesとanimationを書く方法より短くコードを書くことができるわけです。
こちらブラウザ対応は確認しないとですがとても便利ですね。
先ほどの話に戻りますが、transitionがうまく動作しない件についてstarting-styleを使用することで解決できる場合があります。
CSSを以下のように修正しましょう。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
@starting-style {
opacity: 0;
}
transition: opacity 2s;
opacity: 1;
padding: 32px;
}
/* ここを修正 */
.remain {
display: none;
transition: opacity 2s;
}
/* ここを修正 */
.remain.show {
@starting-style {
opacity: 0;
}
display: block;
opacity: 1;
}
display: block;が指定してあるremain.showの部分にてstarting-styleを使ったopacityの変化を記載しました。
先ほどはopacityをdisplay: none;の方とdisplay: block;の方の両方に使って指定していたので動作しませんでしたが、こちらの方法であれば期待した動作になります。
display: none;がない場所でstarting-styleを使ったプロパティの指定をすればtransitionを確実に実行できるようになったのは非常に嬉しいですね。
ぜひ皆さんも違いを体験してみてください。