必須フォーム入力付きのダイアログを閉じる

ダイアログ内のフォームに必須入力項目がある場合、ユーザーエージェントは、必須入力項目に値が入力されるまで、ダイアログを閉じることができません。このようなダイアログを閉じるには、[閉じる]ボタンに formnovalidate 属性を使用するか、[閉じる]ボタンがクリックされたときにダイアログオブジェクトの close() メソッドを呼び出すかしてください。

html

  
    

JavaScript

js
const showBtn = document.getElementById("show-dialog");
const dialog = document.getElementById("dialog");
const jsCloseBtn = dialog.querySelector("#js-close");

showBtn.addEventListener("click", () => {
  dialog.showModal();
});

jsCloseBtn.addEventListener("click", (e) => {
  e.preventDefault();
  dialog.close();
});

結果

出力から、[通常 閉じる]ボタンを使用してダイアログを閉じることができないことが分かります。しかし、[無検証 閉じる]ボタンの formnovalidate 属性を使用してフォームの検証をバイパスすれば、ダイアログを閉じることができます。プログラム上では、dialog.close() を使用しても同様にダイアログを閉じることができます。

アニメーションするダイアログ

要素は、非表示時には display: none; 表示時には display: block; と設定され、最上位レイヤーおよびアクセシビリティツリーから削除されたり、追加されたりします。したがって、 要素をアニメーションさせるには、 display プロパティをアニメーション化する必要があります。対応ブラウザーでは、display プロパティを離散的なアニメーション型で変化させてアニメーション化します。具体的には、ブラウザーは none と他の display 値を交互に切り替えることで、アニメーション化されたコンテンツがアニメーションの全期間にわたって表示されるようにします。

例えば、

  • displaynone から block(あるいは他の可視の display 値)にアニメーションする場合、アニメーション再生時間の 0% で値が block に切り替わり、常に表示されます。
  • displayblock(または他の可視の display 値)から none へのアニメーションでは、アニメーション再生時間の 100% の時点で値が none に切り替わるため、全体を通して表示されます。

メモ: CSS トランジションを使用してアニメーションを行う場合、上記の動作を有効にするには transition-behavior: allow-discrete を設定する必要があります。CSS アニメーションでアニメーションを行う場合、この動作は既定では利用でき、同等の手順は必要ありません。

dialog 要素のトランジション

CSS トランジションで

をアニメーションさせる場合、以下の機能が要求されます。

@starting-style アットルール

に設定されたプロパティの、開かれるたびにトランジションする開始値のセットを提供します。これは予期せぬ動作を避けるために必要です。既定では、CSS トランジションは、可視要素のプロパティが 1 つの値から別の値に変更された場合のみ発生します。要素の最初のスタイル更新時や、display の型が none から別の型に変更された場合には発生しません。

display プロパティ

トランジションのリストに display を追加すると、トランジションの再生時間中、

display: block(またはダイアログが開いている状態として設定されている他の可視 display 値)のままになり、他にもトランジションが確実に表示されます。

overlay プロパティ

トランジションのリストに overlay が含まれていると、最上位レイヤーから

が確実に除去されるまでトランジションが完了するまで遅延され、トランジションが確実に表示されるようになります。

transition-behavior プロパティ

transition-behavior: allow-discretedisplayoverlay トランジション(または transition 一括指定)に設定すると、既定ではアニメーションできないこれら2つのプロパティで離散トランジションが有効になります。

この機能がどのようなものか見ていくために、例えば次のような例を挙げてみましょう。

HTML

この HTML は

要素と、ダイアログを表示させるためのボタンを格納しています。さらに、 要素には、それ自体を閉じさせるためのボタンがもう一つ格納されています。

html

  ここがコンテンツ
  



CSS

CSS では、@starting-style ブロックを記述して、opacity および transform プロパティのトランジション開始時のスタイル、dialog[open] 状態のトランジション終了時のスタイル、

が表示された後に元の状態に戻る際の既定の dialog 状態のスタイルを定義します。注意してほしいのは、 transition リストには、これらのプロパティだけでなく、displayoverlay プロパティも含まれ、それぞれに allow-discrete が設定されていることです。

また、開いたときに現れる

の背後に現れる ::backdropbackground-color プロパティに開始時のスタイル値を設定し、素敵な暗転アニメーションを指定しました。 dialog[open]::backdrop セレクターは、ダイアログが開いているときに、 要素の背景のみを選択します。

css
/*   開いた状態のダイアログ  */
dialog[open] {
  opacity: 1;
  transform: scaleY(1);
}

/*   閉じた状態のダイアログ   */
dialog {
  opacity: 0;
  transform: scaleY(0);
  transition:
    opacity 0.7s ease-out,
    transform 0.7s ease-out,
    overlay 0.7s ease-out allow-discrete,
    display 0.7s ease-out allow-discrete;
  /* transition: all 0.7s allow-discrete;
  と等しい*/
}

/*   開く前の状態  */
/* 詳細度が同じであるため、前の dialog[open] ルールの後に置かなければ効果がありません */
@starting-style {
  dialog[open] {
    opacity: 0;
    transform: scaleY(0);
  }
}

/* ダイアログがモーダルで最上位に来た場合に :backdrop をトランジションする */
dialog::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;
  と等しい */
}

dialog[open]::backdrop {
  background-color: rgb(0 0 0 / 25%);
}

/* この開始スタイル設定ルールは、上記のセレクター内にネストすることができません。
入れ子セレクターは擬似要素を表すことができないからです。 */

@starting-style {
  dialog[open]::backdrop {
    background-color: rgb(0 0 0 / 0%);
  }
}
JavaScript

JavaScript で、表示ボタンと閉じるボタンにイベントハンドラーを追加し、クリックされたときに

を表示させたり閉じたりするイベントを発生させます。

js
const dialogElem = document.getElementById("dialog");
const showBtn = document.querySelector(".show");
const closeBtn = document.querySelector(".close");

showBtn.addEventListener("click", () => {
  dialogElem.showModal();
});

closeBtn.addEventListener("click", () => {
  dialogElem.close();
});
結果

このコードは次のように表示されます。

メモ:

は、表示される時点では常に display: none から display: block に変更されるため、項目遷移が発生するたびに、@starting-style スタイルから dialog[open] スタイルにトランジションします。 が閉じられると、dialog[open] 状態から既定の dialog 状態にトランジションします。

このような場合、項目への入力時と出力時のスタイル設定のトランジションが異なることが可能です。この例については、「開始スタイルを使用する場合のデモ」をご覧ください。

dialog のキーフレームアニメーション

CSS のキーフレームアニメーションで

をアニメーションさせる場合、トランジションとのいくつかの違いに注意する必要があります。

  • @starting-style は提供しません。
  • キーフレームには display を記載します。これはアニメーション全体、または別の none 以外の表示値が指定されるまでの表示値となります。
  • 離散アニメーションを明示的に有効にする必要はありません。キーフレーム内に allow-discrete に相当するものはありません。
  • また、キーフレーム内で overlay を設定する必要もありません。 display のアニメーションが の表示から非表示へのアニメーションを処理します。

この例を見て、どのようなものか見ていきましょう。

HTML

最初の HTML には、

要素と、ダイアログを表示させるためのボタンがあります。さらに、 要素には、それ自体を閉じるためのボタンが格納されています。

html

  ここがコンテンツです
  



CSS

CSSでは、

を閉じられた状態と表示させた状態の間でアニメーションさせるためのキーフレームを定義し、さらに、の背景のフェードインアニメーションも定義しています。ダイアログボックスのアニメーションには、実際のアニメーション効果が再生時間全体にわたって確実に表示されるようにするための display のアニメーションが含まれます。 バックグラウンドのフェードアウトのアニメーションは不可能であることに注意してください。背景は、ダイアログボックスが閉じられるとすぐに DOM から除去されるため、アニメーション化する何かがあるわけではありません。

css
dialog {
  animation: fade-out 0.7s ease-out;
}

dialog[open] {
  animation: fade-in 0.7s ease-out;
}

dialog[open]::backdrop {
  animation: backdrop-fade-in 0.7s ease-out forwards;
}

/* Animation keyframes */

@keyframes fade-in {
  0% {
    opacity: 0;
    transform: scaleY(0);
    display: none;
  }

  100% {
    opacity: 1;
    transform: scaleY(1);
    display: block;
  }
}

@keyframes fade-out {
  0% {
    opacity: 1;
    transform: scaleY(1);
    display: block;
  }

  100% {
    opacity: 0;
    transform: scaleY(0);
    display: none;
  }
}

@keyframes backdrop-fade-in {
  0% {
    background-color: rgb(0 0 0 / 0%);
  }

  100% {
    background-color: rgb(0 0 0 / 25%);
  }
}

body,
button {
  font-family: system-ui;
}
JavaScript

最後に、JavaScript でボタンにイベントハンドラーを追加し、

を表示させたり閉じたりできるようにします。

js
const dialogElem = document.getElementById("dialog");
const showBtn = document.querySelector(".show");
const closeBtn = document.querySelector(".close");

showBtn.addEventListener("click", () => {
  dialogElem.showModal();
});

closeBtn.addEventListener("click", () => {
  dialogElem.close();
});
結果

このコードは次のように表示されます。

技術的概要

コンテンツカテゴリー フローコンテンツ, 区分化ルート
許可されている内容 フローコンテンツ
タグの省略 なし。開始タグと終了タグの両方が必須です。
許可されている親要素 フローコンテンツを受け入れるあらゆる要素
暗黙の ARIA ロール dialog
許可された ARIA ロール alertdialog
DOM インターフェイス HTMLDialogElement

仕様書

Specification
HTML
# the-dialog-element

ブラウザーの互換性

関連情報