<dialog>:對話方塊元素

基線 2022

新可用

2022 年 3 月起,此功能可在最新的裝置和瀏覽器版本中使用。此功能可能在較舊的裝置或瀏覽器中不起作用。

<dialog> HTML 元素表示模態或非模態對話方塊或其他互動式元件,例如可關閉的警報、檢查器或子視窗。

HTML <dialog> 元素用於建立模態和非模態對話方塊。模態對話方塊會中斷與頁面其餘部分的互動,使其處於非活動狀態,而非模態對話方塊允許與頁面其餘部分進行互動。

應使用 JavaScript 顯示 <dialog> 元素。使用 .showModal() 方法顯示模態對話方塊,並使用 .show() 方法顯示非模態對話方塊。可以使用 .close() 方法或在提交巢狀在 <dialog> 元素內的 <form> 時使用 dialog 方法關閉對話方塊。也可以透過按 Esc 鍵關閉模態對話方塊。

屬性

此元素包含 全域性屬性

警告:tabindex 屬性不得用於 <dialog> 元素。請參閱 使用說明

open

指示對話方塊處於活動狀態並可供互動。如果未設定 open 屬性,則使用者將看不到對話方塊。建議使用 .show().showModal() 方法呈現對話方塊,而不是 open 屬性。如果使用 open 屬性開啟 <dialog>,則它是非模態的。

注意:雖然可以透過切換 open 屬性的存在來切換非模態對話方塊的開啟和關閉狀態,但不建議使用這種方法。

使用說明

  • 如果 HTML <form> 元素具有 method="dialog" 屬性或用於提交表單的按鈕具有 formmethod="dialog" 設定,則可以使用它們來關閉對話方塊。當透過 dialog 方法提交 <dialog> 中的 <form> 時,對話方塊將關閉,表單控制元件的狀態將儲存但不會提交,並且 returnValue 屬性將設定為啟用的按鈕的值。
  • CSS ::backdrop 偽元素可用於設定模態對話方塊的背景樣式,當使用 HTMLDialogElement.showModal() 方法顯示對話方塊時,該背景顯示在 <dialog> 元素後面。例如,此偽元素可用於模糊、變暗或以其他方式模糊模態對話方塊後面的非活動內容。
  • 應將 autofocus 屬性新增到使用者在開啟模態對話方塊後預期立即與其互動的元素中。如果沒有任何其他元素涉及更直接的互動,建議在對話方塊內的關閉按鈕或對話方塊本身新增 autofocus,如果使用者預期單擊/啟用它以將其關閉。
  • 不要將 tabindex 屬性新增到 <dialog> 元素,因為它不具有互動性並且不會接收焦點。對話方塊的內容(包括對話方塊中包含的關閉按鈕)可以接收焦點並具有互動性。

無障礙

在實現對話方塊時,務必考慮設定使用者焦點的最合適位置。當使用 HTMLDialogElement.showModal() 開啟 <dialog> 時,焦點將設定在第一個巢狀的可聚焦元素上。透過使用 autofocus 屬性明確指示初始焦點放置將有助於確保初始焦點設定在被認為是任何特定對話方塊的最佳初始焦點放置的元素上。如有疑問,因為它可能並不總是知道在對話方塊內可以設定初始焦點的位置,特別是對於在呼叫時動態呈現對話方塊內容的情況,<dialog> 元素本身可能提供最佳的初始焦點放置。

確保提供了一種機制允許使用者關閉對話方塊。確保所有使用者都能關閉對話方塊的最穩健方法是包含一個明確的按鈕來執行此操作,例如確認、取消或關閉按鈕。

預設情況下,透過 showModal() 方法呼叫的對話方塊可以透過按 Esc 鍵關閉。非模態對話方塊預設情況下不會透過 Esc 鍵關閉,並且根據非模態對話方塊的表示內容,可能不希望出現此行為。鍵盤使用者期望 Esc 鍵關閉模態對話方塊;確保實現並維護此行為。如果開啟多個模態對話方塊,則按 Esc 鍵應僅關閉最後顯示的對話方塊。使用 <dialog> 時,此行為由瀏覽器提供。

雖然可以使用其他元素建立對話方塊,但原生<dialog>元素提供了必須複製的可用性和可訪問性功能,如果您出於類似目的使用其他元素。如果您正在建立自定義對話方塊實現,請確保支援所有預期的預設行為並遵循正確的標籤建議。

<dialog>元素以類似於使用 ARIA role="dialog" 屬性的自定義對話方塊的方式由瀏覽器公開。透過showModal()方法呼叫的<dialog>元素隱式地具有aria-modal="true",而透過show()方法呼叫的<dialog>元素或使用open屬性顯示的<dialog>元素或透過更改<dialog>的預設display公開為[aria-modal="false"]。在實現模態對話方塊時,除了<dialog>及其內容之外的所有內容都應使用inert 屬性呈現為惰性。當與HTMLDialogElement.showModal() 方法一起使用<dialog>時,此行為由瀏覽器提供。

示例

僅 HTML 對話方塊

此示例演示了僅使用 HTML 建立非模態對話方塊。由於<dialog>元素中的布林值open屬性,因此頁面載入時對話方塊顯示為開啟狀態。可以透過單擊“確定”按鈕關閉對話方塊,因為<form>元素中的method屬性設定為"dialog"。在這種情況下,不需要 JavaScript 來關閉表單。

html
<dialog open>
  <p>Greetings, one and all!</p>
  <form method="dialog">
    <button>OK</button>
  </form>
</dialog>

結果

注意:重新載入頁面以重置輸出。

此對話方塊最初是開啟的,因為存在open屬性。使用open屬性顯示的對話方塊是非模態的。單擊“確定”後,對話方塊將被關閉,結果框架將為空。當對話方塊被關閉時,沒有提供重新開啟它的方法。因此,顯示非模態對話方塊的首選方法是使用HTMLDialogElement.show()方法。可以透過新增或刪除布林值open屬性來切換對話方塊的顯示,但這並不是推薦的做法。

建立模態對話方塊

此示例演示了一個帶漸變背景的模態對話方塊。當“顯示對話方塊”按鈕被啟用時,.showModal()方法開啟模態對話方塊。可以透過按Esc鍵或在啟用對話方塊內的“關閉”按鈕時透過close()方法關閉對話方塊。

當對話方塊開啟時,瀏覽器預設情況下會將焦點賦予對話方塊內第一個可以聚焦的元素。在此示例中,autofocus 屬性應用於“關閉”按鈕,在對話方塊開啟時將其聚焦,因為這是我們期望使用者在對話方塊開啟後立即與之互動的元素。

HTML

html
<dialog>
  <button autofocus>Close</button>
  <p>This modal dialog has a groovy backdrop!</p>
</dialog>
<button>Show the dialog</button>

CSS

我們可以使用::backdrop偽元素來設定對話方塊背景的樣式。

css
::backdrop {
  background-image: linear-gradient(
    45deg,
    magenta,
    rebeccapurple,
    dodgerblue,
    green
  );
  opacity: 0.75;
}

JavaScript

對話方塊使用.showModal()方法以模態方式開啟,並使用.close()方法關閉。

js
const dialog = document.querySelector("dialog");
const showButton = document.querySelector("dialog + button");
const closeButton = document.querySelector("dialog button");

// "Show the dialog" button opens the dialog modally
showButton.addEventListener("click", () => {
  dialog.showModal();
});

// "Close" button closes the dialog
closeButton.addEventListener("click", () => {
  dialog.close();
});

結果

當模態對話方塊顯示時,它會顯示在任何其他可能存在的對話方塊之上。模態對話方塊外部的所有內容都是惰性的,並且阻止了對話方塊外部的互動。請注意,當對話方塊開啟時,除了對話方塊本身之外,無法與文件進行互動;“顯示對話方塊”按鈕大部分被對話方塊幾乎不透明的背景遮擋,並且處於惰性狀態。

處理對話方塊的返回值

此示例演示了<dialog>元素的returnValue以及如何使用表單關閉模態對話方塊。預設情況下,returnValue是空字串或<dialog>元素內表單中提交按鈕的值(如果存在)。

此示例在啟用“顯示對話方塊”按鈕時開啟一個模態對話方塊。對話方塊包含一個表單,其中包含一個<select>和兩個<button>元素,它們預設為type="submit"。事件偵聽器在選擇選項更改時更新“確認”按鈕的值。如果啟用“確認”按鈕以關閉對話方塊,則按鈕的當前值就是返回值。如果透過按下“取消”按鈕關閉對話方塊,則returnValuecancel

關閉對話方塊時,返回值將顯示在“顯示對話方塊”按鈕下方。如果透過按Esc鍵關閉對話方塊,則不會更新returnValue,並且不會發生close事件,因此<output>中的文字不會更新。

HTML

html
<!-- A modal dialog containing a form -->
<dialog id="favDialog">
  <form>
    <p>
      <label>
        Favorite animal:
        <select>
          <option value="default">Choose…</option>
          <option>Brine shrimp</option>
          <option>Red panda</option>
          <option>Spider monkey</option>
        </select>
      </label>
    </p>
    <div>
      <button value="cancel" formmethod="dialog">Cancel</button>
      <button id="confirmBtn" value="default">Confirm</button>
    </div>
  </form>
</dialog>
<p>
  <button id="showDialog">Show the dialog</button>
</p>
<output></output>

JavaScript

js
const showButton = document.getElementById("showDialog");
const favDialog = document.getElementById("favDialog");
const outputBox = document.querySelector("output");
const selectEl = favDialog.querySelector("select");
const confirmBtn = favDialog.querySelector("#confirmBtn");

// "Show the dialog" button opens the <dialog> modally
showButton.addEventListener("click", () => {
  favDialog.showModal();
});

// "Cancel" button closes the dialog without submitting because of [formmethod="dialog"], triggering a close event.
favDialog.addEventListener("close", (e) => {
  outputBox.value =
    favDialog.returnValue === "default"
      ? "No return value."
      : `ReturnValue: ${favDialog.returnValue}.`; // Have to check for "default" rather than empty string
});

// Prevent the "confirm" button from the default behavior of submitting the form, and close the dialog with the `close()` method, which triggers the "close" event.
confirmBtn.addEventListener("click", (event) => {
  event.preventDefault(); // We don't want to submit this fake form
  favDialog.close(selectEl.value); // Have to send the select box value here.
});

結果

以上示例演示了以下三種關閉模態對話方塊的方法

“取消”按鈕包含formmethod="dialog"屬性,該屬性覆蓋了<form>的預設GET方法。當表單的方法為dialog時,表單的狀態將儲存但不會提交,並且對話方塊將關閉。

如果沒有action,則透過預設的GET方法提交表單會導致頁面重新載入。我們使用 JavaScript 分別阻止提交併使用event.preventDefault()HTMLDialogElement.close()方法關閉對話方塊。

在每個dialog元素中提供關閉機制非常重要。Esc鍵預設情況下不會關閉非模態對話方塊,也不能假設使用者甚至可以訪問物理鍵盤(例如,使用觸控式螢幕裝置且無法訪問鍵盤的使用者)。

關閉帶有必填表單輸入的對話方塊

當對話方塊內的表單具有必填輸入時,使用者代理將僅在您為必填輸入提供值後才允許您關閉對話方塊。要關閉此類對話方塊,請在關閉按鈕上使用formnovalidate屬性,或者在單擊關閉按鈕時在對話方塊物件上呼叫close()方法。

html
<dialog id="dialog">
  <form method="dialog">
    <p>
      <label>
        Favorite animal:
        <input type="text" required />
      </label>
    </p>
    <div>
      <input type="submit" id="normal-close" value="Normal close" />
      <input
        type="submit"
        id="novalidate-close"
        value="Novalidate close"
        formnovalidate />
      <input type="submit" id="js-close" value="JS close" />
    </div>
  </form>
</dialog>
<p>
  <button id="show-dialog">Show the dialog</button>
</p>
<output></output>

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()也將關閉此類對話方塊。

動畫對話方塊

<dialog>在隱藏時設定為display: none;,在顯示時設定為display: block;,以及從/新增到頂層可訪問性樹。因此,為了使<dialog>元素能夠進行動畫處理,需要使display屬性可動畫化。支援的瀏覽器使用離散動畫型別的變化來為display設定動畫。具體來說,瀏覽器將在nonedisplay的另一個值之間切換,以便在整個動畫持續時間內顯示動畫內容。

例如

  • 當將displaynone動畫化為block(或另一個可見的display值)時,該值將在動畫持續時間的0%處翻轉為block,以便在整個過程中可見。
  • 當將displayblock(或另一個可見的display值)動畫化為none時,該值將在動畫持續時間的100%處翻轉為none,以便在整個過程中可見。

注意:當使用CSS 過渡進行動畫處理時,需要設定transition-behavior: allow-discrete以啟用上述行為。當使用CSS 動畫進行動畫處理時,此行為預設可用;不需要等效的步驟。

過渡對話方塊元素

當使用 CSS 過渡為<dialog>設定動畫時,需要以下功能

@starting-style at-rule

為在<dialog>上設定的屬性提供一組起始值,您希望每次開啟它時都從這些值過渡。這是為了避免出現意外行為。預設情況下,CSS 過渡僅在屬性在可見元素上從一個值更改為另一個值時發生;它們不會在元素的首次樣式更新時觸發,或者當display型別從none更改為其他型別時觸發。

display 屬性

display新增到過渡列表中,以便<dialog>在過渡期間保持為display: block(或在對話方塊的開啟狀態下設定的另一個可見的display值),確保其他過渡可見。

overlay 屬性

overlay包含在過渡列表中,以確保將<dialog>從頂層移除的操作延遲到過渡完成,再次確保過渡可見。

transition-behavior 屬性

displayoverlay過渡(或在transition簡寫形式上)上設定transition-behavior: allow-discrete,以在預設情況下不可動畫化的這兩個屬性上啟用離散過渡。

這是一個快速示例,用於演示其外觀。

HTML

HTML 包含一個<dialog>元素,以及一個用於顯示對話方塊的按鈕。此外,<dialog>元素包含另一個用於關閉自身的按鈕。

html
<dialog id="dialog">
  Content here
  <button class="close">close</button>
</dialog>

<button class="show">Show Modal</button>
CSS

在 CSS 中,我們包含一個@starting-style塊,該塊定義了opacitytransform屬性的過渡起始樣式,dialog[open]狀態下的過渡結束樣式,以及預設dialog狀態下的預設樣式,以便在<dialog>出現後過渡回預設樣式。請注意,<dialog>transition列表不僅包含這些屬性,還包含displayoverlay屬性,每個屬性都設定了allow-discrete

我們還在開啟時出現在<dialog>後面的::backdrop上為background-color屬性設定了一個起始樣式值,以提供良好的變暗動畫。dialog[open]::backdrop選擇器僅在對話方塊開啟時選擇<dialog>元素的背景。

css
/*   Open state of the dialog  */
dialog[open] {
  opacity: 1;
  transform: scaleY(1);
}

/*   Closed state of the dialog   */
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;
  /* Equivalent to
  transition: all 0.7s allow-discrete; */
}

/*   Before-open state  */
/* Needs to be after the previous dialog[open] rule to take effect,
    as the specificity is the same */
@starting-style {
  dialog[open] {
    opacity: 0;
    transform: scaleY(0);
  }
}

/* Transition the :backdrop when the dialog modal is promoted to the top layer */
dialog::backdrop {
  background-color: rgb(0 0 0 / 0%);
  transition:
    display 0.7s allow-discrete,
    overlay 0.7s allow-discrete,
    background-color 0.7s;
  /* Equivalent to
  transition: all 0.7s allow-discrete; */
}

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

/* This starting-style rule cannot be nested inside the above selector
because the nesting selector cannot represent pseudo-elements. */

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

JavaScript 將事件處理程式新增到顯示和關閉按鈕,使它們在單擊時顯示和關閉<dialog>

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();
});
結果

程式碼呈現如下

注意:因為<dialog>每次顯示時都會從display: none更改為display: block,所以<dialog>每次入口過渡發生時都會從其@starting-style樣式過渡到其dialog[open]樣式。當<dialog>關閉時,它會從其dialog[open]狀態過渡到預設的dialog狀態。

在這種情況下,入口和出口的樣式過渡可能不同。有關此證明,請參閱我們的起始樣式使用時間演示示例。

對話方塊關鍵幀動畫

當使用 CSS 關鍵幀動畫為<dialog>設定動畫時,需要注意與過渡的一些區別

  • 您不提供@starting-style
  • 您在關鍵幀中包含display值;這將是整個動畫的display值,或者直到遇到另一個非none顯示值。
  • 您不需要顯式啟用離散動畫;關鍵幀內部沒有等效於allow-discrete的內容。
  • 您也不需要在關鍵幀內部設定overlaydisplay動畫處理<dialog>從顯示到隱藏的動畫。

讓我們看一個示例,以便您瞭解其外觀。

HTML

首先,HTML 包含一個<dialog>元素,以及一個用於顯示對話方塊的按鈕。此外,<dialog>元素包含另一個用於關閉自身的按鈕。

html
<dialog id="dialog">
  Content here
  <button class="close">close</button>
</dialog>

<button class="show">Show Modal</button>
CSS

CSS 定義了關鍵幀以在<dialog>的關閉和顯示狀態之間設定動畫,以及<dialog>背景的淡入動畫。<dialog>動畫包括為display設定動畫,以確保實際的可見動畫效果在整個持續時間內保持可見。請注意,無法為背景淡出設定動畫——當<dialog>關閉時,背景會立即從 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 將事件處理程式新增到按鈕,以啟用顯示和關閉<dialog>

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

規範

規範
HTML 標準
# the-dialog-element

瀏覽器相容性

BCD 表格僅在瀏覽器中載入

另請參閱