CSS トランジションの開始時のスタイルを定義する `@starting-style` ルール
`@starting-style` ルールは、CSS トランジションの開始時のスタイルを定義するためのアットルールです。CSS トランジションの既定のルールでは前回のスタイル変更イベントでレンダリングされていなかった要素では、アニメーションが適用されない、`display: none` から他の値に変更した場合にアニメーションが適用されないといった問題があります。`@starting-style` ルールを使用することでこれらの問題を解決できます。
@starting-style
ルールは、CSS トランジションの開始時のスタイルを定義するためのアットルールです。@starting-style
アットルールは以下の 2 通りの記法で定義されます。
- 独立したブロックとして記述する方法
@starting-style {
.box {
background-color: red;
}
}
- 既存のルールセットに入れ子にする方法
.box {
background-color: red;
@starting-style {
background-color: blue;
}
}
@starting-style
ルールが必要なのか
なぜ CSS トランジションは、要素のスタイルが変化する際にアニメーションを適用するための仕組みです。CSS トランジションの既定のルールでは以下のような問題があげられます。
- 前回のスタイル変更イベントでレンダリングされていなかった要素では、アニメーションが適用されない
display: none
から他の値に変更した場合にアニメーションが適用されない
1 つ目の問題について詳しく見ていきます。JavaScript を用いて DOM に動的に要素を追加する例を考えてみましょう。以下の例では、ボタンをクリックすると box
クラスを持つ要素が追加されます。
const button = document.querySelector("#add");
const container = document.querySelector(".container");
button.addEventListener("click", () => {
const box = document.createElement("div");
box.classList.add("box");
container.appendChild(box);
});
box
クラスを持つ要素が出現する際にアニメーションを適用したい場合、CSS トランジションを使用すると以下のような記述が思いつくかもしれません。はじめに
CSS で初期値として opacity: 0
を設定しておきます。
.box {
opacity: 0;
transition: opacity 1s;
}
そして、JavaScript で要素が追加される際に opacity
プロパティを変更します。
button.addEventListener("click", () => {
const box = document.createElement("div");
box.classList.add("box");
container.appendChild(box);
box.style.opacity = 1;
});
しかし、この方法では要素が追加される瞬間にアニメーションが適用されません。opacity: 1;
は要素のスタイルが計算される前に設定されるため、opacity: 0;
ではなく opacity: 1;
が初期値とみなされてしまうためです。
この問題を解決するためには、getBoundingClientRect()
メソッドを使用して強制的に要素のスタイルを再計算するようなハックが必要でした。
button.addEventListener("click", () => {
const box = document.createElement("div");
box.classList.add("box");
container.appendChild(box);
box.getBoundingClientRect();
box.style.opacity = 1;
});
もしくは requestAnimationFrame()
を使用して要素が描画されたことを確認してからアニメーションを適用する方法もありました。
button.addEventListener("click", () => {
const box = document.createElement("div");
box.classList.add("box");
container.appendChild(box);
requestAnimationFrame(() => {
box.style.opacity = 1;
});
});
@starting-style
ルールを使用する
DOM に要素を追加する際のアニメーションに @starting-style
ルールを使用することで要素が動的に DOM に追加される際のアニメーションの問題を解決できます。JavaScript 上で opacity
プロパティを変更する代わりに、@starting-style
ルールを使用して初期スタイルを定義します。
.box {
opacity: 1;
transition: opacity 1s;
@starting-style {
opacity: 0;
}
}
もしくは、@starting-style
ルールを独立したブロックとして記述することもできます。
.box {
opacity: 1;
transition: opacity 1s;
}
@starting-style {
.box {
opacity: 0;
}
}
@starting-style
アットルールのブロック内でも外のスコープと同じ 詳細度 が適用されます。そのため @starting-style
ルール内の記述が確実に適用されるようするために、元のルールより後に記述する必要があります。元のルールが後に定義されている場合上書きされるため、@starting-style
ルールが適用されません。@starting-style
を入れ子にしている場合にはこのような問題は発生しません。
ポップオーバーの開閉時にアニメーションを適用する
ポップオーバー のように 最上位レイヤー に表示される要素の開閉時にアニメーションを適用したい場合には、@starting-style
ルールが有効な手段となります。ポップオーバーは開いている状態と閉じている状態を display: none
により切り替えるため、CSS トランジションではアニメーションを適用できません。
[popover] {
transform: scaleX(0);
}
[popover]:popover-open {
transform: scaleX(1);
transition: transform 1s;
}
以下のように @starting-style
ルールを入れ子に、そこにトランジションの開始時のスタイルを定義することで、ポップオーバーが開いた瞬間にアニメーションが適用されるようになります。
[popover]:popover-open {
transform: scaleX(1);
transition: transform 1s;
@starting-style {
transform: scaleX(0);
}
}
まとめ
@starting-style
ルールは CSS トランジションの開始時のスタイルを定義するためのアットルール- CSS トランジションでは要素が動的に DOM に追加される際にアニメーションが適用されない、
display: none
から他の値に変更した場合にアニメーションが適用されないといった問題がある @starting-style
ルールを使用することで上記のような問題を解決できる