@starting-style
Limited availability
This feature is not Baseline because it does not work in some of the most widely-used browsers.
@starting-style
は CSS のアットルールで、トランジションさせる要素に設定されるプロパティ群の開始値を定義するために使用します。これらのプロパティは、最初に要素のスタイルが更新されたとき、つまり要素が前回読み込まれたページに最初に表示されたときに設定されるものです。
構文
@starting-style
アットルールは次の 2 通りの方法で使用することができます。
-
独立したブロックとする方法。この場合、スタイル宣言を定義し、適用する要素を選択する 1 つ以上のルールセットを記述します。
css@starting-style { ルールセット }
-
既存のルールセット内に入れ子にする方法。この場合、そのルールセットによってすでに選択されている要素のプロパティ値を定義する 1 つ以上の宣言が入ります。
cssselector { /* 既存のルールセット */ /* ... */ @starting-style { 宣言 } }
解説
予期しない動作を避けるため、既定では CSS トランジション は要素の初期スタイル更新時や、 display
型が none
から別の値に変わった時には発生しません。開始スタイル設定のトランジションを有効にするには、 @starting-style
ルールが必要です。これは前回状態を持たない要素に開始スタイルを提供し、トランジションするプロパティ値を定義します。
@starting-style
は、最上位レイヤーに表示される要素(ポップオーバーやモーダルダイアログ (<dialog>
) など)、 display: none
に変更される要素、 DOM に追加されたり除去されたりする要素の出現・消滅トランジションを作成する場合に特に有益です。
メモ: @starting-style
は CSS トランジションにのみ関係します。 CSS アニメーションを使用してそのような効果を実装する場合、 @starting-style
は必要ありません。例については CSS アニメーションの使用を参照してください。
@starting-style
を使用するには、単独のルールとして使用する方法と、ルールセットの中に入れ子にして使用する方法とがあります。
ポップオーバーを表示させたとき(つまり最上位レイヤーに追加したとき)にアニメーションさせたい場合を考えてみましょう。開くためのポップオーバーのスタイルを指定する「元ルール」は次のようになります(下記のポップオーバーの例を参照してください)。
[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
}
最初の方法でアニメーションするポップオーバーのプロパティの開始値を指定するには、 CSS の中に独立した @starting-style
ブロックを記述します。
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}
メモ: @starting-style
アットルールと「元ルール」の詳細度
は同じになります。確実にスタイル設定が反映されるようにするには、 @starting-style
アットルールを「元ルール」の後に記載してください。もし @starting-style
アットルールを「元ルール」の前に指定すると、元のスタイル設定が開始時のスタイル設定を上書きします。
入れ子方式を使用してポップオーバーの開始スタイルを指定するには、 @starting-style
ブロックを「元ルール」の中に入れます。
[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
@starting-style {
opacity: 0;
transform: scaleX(0);
}
}
開始スタイルは正確にはいつ使われるのか
要素が @starting-style
のスタイルからトランジションするのは、要素が最初に DOM で表示されるとき、または display: none
から可視値にトランジションするときであることを理解しておくことが重要です。初期状態が表示状態である場合にトランジションで戻る場合は、すでに DOM で表示されているので @starting-style
スタイルは使用されません。代わりに、その要素の既定の状態に存在するスタイル設定に戻ります。
効果として、このような状況で管理すべきスタイル状態には、開始スタイルの状態、トランジション後の状態、既定の状態の 3 つがあります。このような場合、 "to" と "from" のトランジションは異なるものになる可能性があります。下記開始スタイルを使用する場合のデモの例で、その証拠を見ることができます。
形式文法
例
基本的な @starting-style の使い方
要素の background-color
を、初期レンダリング時に透明から緑色に遷移させます。
#target {
transition: background-color 1.5s;
background-color: green;
}
@starting-style {
#target {
background-color: transparent;
}
}
要素が display
の値を none
との間で変更したときに、要素の opacity
をトランジションさせます。
#target {
transition-property: opacity, display;
transition-duration: 0.5s;
display: block;
opacity: 1;
@starting-style {
opacity: 0;
}
}
#target.hidden {
display: none;
opacity: 0;
}
開始スタイルを使用する場合のデモ
この例では、ボタンを押して <div>
要素を作成し、class
に showing
を与えて DOM に追加しています。
showing
には @starting-style
として background-color: red
を指定しており、トランジション先としては background-color: blue
を指定しています。既定の div
ルールセットには background-color: yellow
をしており、 transition
も設定しています。
まず <div>
が DOM に追加されると、背景が赤から青に変化するのがわかります。タイムアウト後、 JavaScript で <div>
から showing
クラスを除去します。この点で、背景は赤ではなく青から黄色に戻ります。これは、要素が最初に DOM にレンダリングされるときにのみ、開始スタイルが使用されることを表しています。一度現れた要素は、設定した既定のスタイルに戻ります。
さらにタイムアウトしたら、 DOM から <div>
を完全に除去し、例を初期状態にリセットして、再び実行できるようにしています。
HTML
<button><code><div></code> を表示</button>
CSS
div {
background-color: yellow;
transition: background-color 3s;
}
div.showing {
background-color: skyblue;
}
@starting-style {
div.showing {
background-color: red;
}
}
JavaScript
const btn = document.querySelector("button");
btn.addEventListener("click", () => {
btn.disabled = true;
const divElem = document.createElement("div");
divElem.classList.add("showing");
document.body.append(divElem);
setTimeout(() => {
divElem.classList.remove("showing");
setTimeout(() => {
divElem.remove();
btn.disabled = false;
}, 3000);
}, 3000);
});
結果
このコードは次のように表示されます。
ポップオーバーのアニメーション
この例では、ポップオーバーを CSS トランジションによってアニメーションしています。基本的な出現・消滅のアニメーションは、 transition
プロパティを使用して提供しています。
HTML
この HTML では、 <div>
要素に popover 属性を用いてポップオーバーとして宣言し、 <button>
要素に popovertarget 属性を用いてポップオーバーの表示コントロールとして指定しています。
<button popovertarget="mypopover">ポップオーバーを表示</button>
<div popover="auto" id="mypopover">これがポップオーバーです。アニメーションします。</div>
CSS
この例では opacity
と transform
(具体的には、水平方向に変倍する座標変換)という 2 つのプロパティをアニメーションさせて、ポップオーバーをフェードイン/フェードアウトさせたり、水平方向に拡大/縮小させたりします。
html {
font-family: Arial, Helvetica, sans-serif;
}
[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
}
[popover] {
font-size: 1.2rem;
padding: 10px;
/* 消滅アニメーションの最終状態 */
opacity: 0;
transform: scaleX(0);
transition:
opacity 0.7s,
transform 0.7s,
overlay 0.7s allow-discrete,
display 0.7s allow-discrete;
/* transition: all 0.7s allow-discrete;
と等価 */
}
/* [popover]:popover-open ルールの後に入れる */
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}
/* ポップオーバーの背後のトランジション */
[popover]::backdrop {
background-color: rgb(0 0 0 / 0%);
transition:
display 0.7s allow-discrete,
overlay 0.7s allow-discrete,
background-color 0.7s;
/* transition: all 0.7s allow-discrete;
と等価 */
}
[popover]:popover-open::backdrop {
background-color: rgb(0 0 0 / 25%);
}
/* 入れ子 (&) は擬似要素には対応していないので、
独立した開始スタイルのブロックを指定します。 */
@starting-style {
[popover]:popover-open::backdrop {
background-color: rgb(0 0 0 / 0%);
}
}
これを実現するために、これらのプロパティの開始状態にはポップオーバー要素の既定の非表示状態を([popover]
で選択して)設定し、終了状態にはポップオーバー要素が開いた状態を(:popover-open
擬似クラスで選択して)設定しています。
そして、 transition
プロパティを設定し、 2 つの状態の間でアニメーションを行います。アニメーションの始める状態には @starting-style
アットルールを記載して、アニメーションの初期状態を設定しています。
アニメーションする要素は、表示されると最上位レイヤーへ移動し、(display: none
で)非表示になると最上位レイヤーから除去されるため、両方向で確実にアニメーションが動作するように、さらにいくつかの段階が必要になります。
display
をトランジション後の要素のリストに追加することで、アニメーションする要素が出現・消滅の両方のアニメーション中に確実に表示される(display: block
などのdisplay
の可視値に設定する)ようにします。これがなければ、消滅アニメーションは表示されません。その結果、ポップオーバーはただ消えてしまいます。アニメーションを有効にするために、transition-behavior: allow-discrete
値も一括指定で設定されていることに注意してください。overlay
をトランジション後の要素のリストに追加して、要素を最上位レイヤーから除去するのをアニメーションが終わるまで確実に延期するようにします。これは、このような単純なアニメーションでは大差ありませんが、より複雑なケースでは、これを行わないと、要素がオーバーレイからすばやく除去され、アニメーションが滑らかでなくなったり、効果的でなくなったりすることがあります。この場合も、アニメーションを行うにはtransition-behavior: allow-discrete
が必要です。
メモ: また、開いたときにポップオーバーの背後に現れる ::backdrop
のトランジションも記載し、暗転するアニメーションも提供しています。 [popover]:popover-open::backdrop
はポップオーバーが開くための背景を選択するために使用します。
結果
このコードは次のように表示されます。
メモ: ポップオーバーは表示されるたびに display: none
から display: block
に変化するので、表示トランジションが発生するたびに @starting-style
スタイルから [popover]:popover-open
スタイルに遷移します。ポップオーバーが閉じられたとき、その [popover]:popover-open
状態から既定の [popover]
状態に遷移します。
メモ: <dialog>
要素とその背景の表示・非表示を遷移させる例は、 <dialog>
リファレンスページのダイアログ要素の遷移で探すことができます。
DOM に追加・除去される要素のトランジション
この例には、押されると新しい要素を <section>
コンテナーに追加するボタンがあります。各要素の中には、押されたときにその要素を除去するボタンがあります。この例は、要素を DOM に追加したり、除去したりするときに、トランジションを使用してアニメーションを行う使用する方法を示しています。
HTML
<button>新しい列を作成</button>
<section></section>
JavaScript
JavaScript により、要素の追加や削除ができるようにします。
const btn = document.querySelector("button");
const sectionElem = document.querySelector("section");
btn.addEventListener("click", createColumn);
function randomColor() {
function randomNum() {
return Math.floor(Math.random() * 255);
}
return `rgb(${randomNum()} ${randomNum()} ${randomNum()})`;
}
function createColumn() {
const divElem = document.createElement("div");
divElem.style.backgroundColor = randomColor();
const closeBtn = document.createElement("button");
closeBtn.textContent = "✖";
closeBtn.setAttribute("aria-label", "close");
divElem.append(closeBtn);
sectionElem.append(divElem);
closeBtn.addEventListener("click", () => {
divElem.classList.add("fade-out");
setTimeout(() => {
divElem.remove();
}, 1000);
});
}
「新しい列を作成」ボタンをクリックすると、 createColumn()
関数が呼び出されます。これは、ランダムに生成された背景色を持つ <div>
要素と、その <div>
を閉じるための <button>
要素を作成します。そして、<button>
を <div>
に、<div>
を <section>
コンテナーに追加します。
そして、 addEventListener()
によって閉じるボタンにイベントリスナーを追加します。閉じるボタンをクリックすると、 2 つのことが行われます。
<div>
にfade-out
クラスを追加します。クラスを追加すると、そのクラスに設定した消滅アニメーションが起動します。- 1000 ミリ秒遅れて
<div>
を取り除きます。アニメーションが終わるまで、setTimeout()
は<div>
の DOM からの除去を遅らせます(Element.remove()
経由)。
CSS
transition
を記述して、それぞれの列が追加されたり除去されたりする際に、 opacity
と scale
をアニメーションさせます。
div {
flex: 1;
border: 1px solid gray;
position: relative;
background: linear-gradient(
to right,
rgb(255 255 255 / 0%),
rgb(255 255 255 / 50%)
);
opacity: 1;
scale: 1 1;
transition:
opacity 0.7s,
scale 0.7s,
display 0.7s allow-discrete,
all 0.7s allow-discrete;
/* transition: all 0.7s allow-discrete;
と等価*/
}
/* `div` ルールの後に記述 */
@starting-style {
div {
opacity: 0;
scale: 1 0;
}
}
.fade-out {
opacity: 0;
display: none;
scale: 1 0;
}
div > button {
font-size: 1.6rem;
background: none;
border: 0;
text-shadow: 2px 1px 1px white;
border-radius: 15px;
position: absolute;
top: 1px;
right: 1px;
cursor: pointer;
}
opacity
および scale
をそれぞれの <div>
が DOM に追加された際にアニメーションさせ、 DOM から削除された際に逆のアニメーションを行うために、次のことを行います。
div { ... }
ルールにトランジションさせたいプロパティの終了状態を指定します。@starting-style
ブロック内のプロパティでトランジションの開始状態を指定します。.fade-out
ルールの中で消滅アニメーションを指定します。これは、閉じるボタンが押されたときに JavaScript が<div>
要素に割り当てるクラスです。透明度と変倍の終了状態を設定するほかに、<div>
要素にdisplay: none
を設定します。 UI から除去されたときにすぐに利用できなくなるようにします。transition
のリストをdiv { ... }
ルールの中で指定し、opacity
、scale
、display
をアニメーションさせます。display
については、アニメーションするように一括指定によってtransition-behavior: allow-discrete
の値も設定されることに注意してください。
結果
最終的な結果はこのようになります。
仕様書
Specification |
---|
CSS Transitions Level 2 # defining-before-change-style |
ブラウザーの互換性
BCD tables only load in the browser
関連情報
- CSS トランジションモジュール
overlay
transition-behavior
CSSStartingStyleRule
- Four new CSS features for smooth entry and exit animations (developer.chrome.com, 2023)