@starting-styleが便利! モーダルやPopoverの「ふわっと出る」をCSSだけで自然に作る方法

はじめに

モーダルやポップオーバーを実装するとき、「閉じるアニメーションは付けやすいのに、開く瞬間は急に出てしまう」という場面がよくあります。これまでは、表示前のクラスを一瞬だけ当てたり、JavaScriptでタイミングをずらしたりして、少し無理やり整えることも珍しくありませんでした。

そこで使いやすいのが、CSSの@starting-styleです。要素が最初に表示されるときの出発点をCSS側で持てるので、入場アニメーションをかなり素直に書けます。

2026年3月30日時点では、MDNでもBaseline 2024として整理されており、最近のブラウザを前提にした案件なら検討しやすくなってきました。この記事では、基本の考え方から、popoverdialogのような実務でよく使うUIへの応用までをまとめます。

@starting-styleとは

@starting-styleは、要素が最初に表示されるときに「どの見た目から遷移を始めるか」を指定するためのCSSルールです。

通常のCSS Transitionは、前の状態から次の状態へ変わるときに動きます。ただ、最初の表示時には「前の状態」がないため、opacitytransformを書いても、そのまま最終状態で表示されることがあります。

そこで@starting-styleを使うと、「表示された瞬間のスタート地点」を明示できます。たとえば、最終状態はopacity: 1でも、開始時だけopacity: 0として扱えるので、自然なフェードインが成立します。

基本の使い方

最初は、通知カードが画面に追加されたときに、少し下から浮き上がる例です。このコードでは、表示後の見た目を通常ルールに書き、表示直後だけ使う値を@starting-styleに分けています。

<section class="notice-list">
  <div class="notice-card is-visible">
    保存が完了しました
  </div>
</section>
HTML
.notice-card {
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity 240ms ease,
    transform 240ms ease;
}

@starting-style {
  .notice-card.is-visible {
    opacity: 0;
    transform: translateY(12px);
  }
}
CSS

このコードでやっていることはシンプルです。普段の.notice-cardは見えている完成形として定義し、最初に表示されるときだけopacity: 0translateY(12px)から始めています。

従来は、表示前クラスと表示後クラスをJavaScriptで細かく切り替えることが多かった部分ですが、@starting-styleならCSSだけで「最初の一歩」を持てるのが分かりやすいところです。

便利な使いどころ

特に相性がいいのは、次のようなUIです。

  • popoverを使ったヘルプやメニュー
  • <dialog>を使った確認モーダル
  • 条件分岐でDOMに追加されるトースト通知
  • フィルターやサイドパネルの入退場

どれも「表示される瞬間だけ少し気持ちよくしたい」一方で、JavaScriptでアニメーション制御まで持ち込みたくない場面です。

最近はpopoverdialogをHTML標準の仕組みで組みやすくなっているので、@starting-styleを組み合わせると、開閉制御はHTMLに寄せつつ、見た目だけCSSで整える構成にしやすくなります。

応用コード

ここでは、popoverで開くヘルプパネルに入退場アニメーションを付ける例を見てみます。ポイントは、入場のために@starting-styleを使い、退出時に途中で消えないようdisplayも一緒に遷移対象へ含めることです。

<button class="help-button" popovertarget="profile-help">
  入力ルールを見る
</button>

<div class="help-popover" popover="auto" id="profile-help">
  表示名は24文字以内。記号は一部使えません。
</div>
HTML
.help-popover {
  inline-size: min(320px, calc(100vw - 32px));
  padding: 16px 18px;
  border: 0;
  border-radius: 14px;
  background: #111827;
  color: #f9fafb;
  box-shadow: 0 18px 40px rgba(15, 23, 42, 0.24);

  opacity: 0;
  transform: translateY(8px) scale(0.98);
  transition:
    opacity 180ms ease,
    transform 180ms ease,
    display 180ms allow-discrete;
}

.help-popover:popover-open {
  opacity: 1;
  transform: translateY(0) scale(1);
}

@starting-style {
  .help-popover:popover-open {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
  }
}
CSS

この例では、閉じているときの.help-popoverを「退出後の見た目」として扱い、開いているときの:popover-openで最終状態を定義しています。@starting-styleは、開いた瞬間だけその開始位置を補う役目です。

実務ではこの形にしておくと、JavaScript側は「開く・閉じる」の制御だけに集中できます。たとえばフォーム補助、テーブルの列説明、設定画面の詳細ヘルプなど、細かいUIを増やしても実装の重さが増えにくいです。

注意点

  • @starting-styleは通常ルールより後ろに置く
    同じ詳細度のルールなら、後ろに書かれたほうが効きます。Chrome for Developersでも、開始スタイルが上書きされないよう配置順に注意する案内があります。
  • displayの切り替えを含むならallow-discreteも確認する
    開閉時にdisplay: noneが絡むUIでは、transition-behavior: allow-discreteまたはtransition: ... allow-discreteが必要になることがあります。これがないと、閉じるアニメーションが途中で見えなくなることがあります。
  • 古めのブラウザでは差が出る
    @starting-style自体はMDNでBaseline 2024ですが、関連する離散アニメーションやoverlayは機能差が残ることがあります。幅広いサポートが必要な案件では、対象ブラウザで実機確認しておくのが安全です。
  • すべてをアニメーションさせない
    管理画面や業務画面では、動きが増えすぎると逆に使いづらくなります。通知、補助UI、モーダルのように「出たことが伝わると助かる場所」へ絞ると、ちょうどよく効きます。

まとめ

@starting-styleは、これまで少し扱いづらかった「最初に表示される瞬間」のアニメーションを、CSS側で素直に書けるようにしてくれる機能です。特にpopoverdialogのような標準UIと組み合わせると、JavaScriptの責務を増やさずに見た目を整えやすくなります。

まずはトースト通知やヘルプパネルのような小さなUIから試すのがおすすめです。入場だけでも自然になると、画面全体の触り心地がかなり変わって見えます。

ポイント

  • 入場アニメーションのためにJavaScriptでクラス切り替えを増やしたくないときに効く
  • popoverdialogと組み合わせると標準機能ベースで組みやすい
  • displayが絡む退出アニメーションではallow-discreteもセットで考える

参考リンク

read next