<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 表格仅在浏览器中加载

另请参阅