網頁功能:
<dialog closedby>
現代模態對話方塊通常支援「輕觸關閉」,使用者只要點選或輕觸背景 (對話方塊以外的區域),即可關閉對話方塊。closedby 屬性提供宣告式方法,不需自訂 JavaScript 即可啟用這項行為。
導入作業
如要啟用輕觸關閉功能,請按照下列步驟操作:
- 將
closedby="any"新增至<dialog>元素。 - 使用
dialog.showModal()開啟對話方塊。
屬性值
any:啟用輕觸關閉 (點選背景)、關閉要求 (Esc鍵) 和開發人員機制 (例如dialog.close())。closerequest:僅啟用「關閉要求」和開發人員機制。這是互動視窗對話方塊的預設值。none:只有開發人員機制可以關閉對話方塊。
設定背景幕樣式
使用 showModal() 將對話方塊開啟為互動視窗時,瀏覽器會產生 ::backdrop 虛擬元素。這個背景會覆蓋整個可視區域,並直接位於對話方塊後方。
/* Style the backdrop to indicate the dialog is modal */
dialog::backdrop {
background-color: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(2px); /* Optional: add blur for modern browsers */
}
範例
<!-- MANDATORY: Use closedby="any" to enable light-dismiss behavior -->
<dialog id="myDialog" closedby="any" aria-labelledby="dialogTitle">
<form method="dialog">
<h2 id="dialogTitle">Feedback</h2>
<p>Click outside this box or press Esc to dismiss.</p>
<button type="submit">Close</button>
</form>
</dialog>
<button onclick="document.getElementById('myDialog').showModal()">Open Dialog</button>
限制與無障礙功能
- 必要:使用
closedby="any"以宣告方式啟用輕觸關閉功能。 - 強制:一律使用
showModal()開啟互動視窗對話方塊。這可確保對話方塊位於頂層、焦點受限,且Esc鍵會受到處理。 - 建議做法:使用
aria-labelledby或aria-label為對話方塊提供無障礙元素名稱。 - 請勿:將
closedby用於非互動式對話方塊 (使用show()開啟),因為這類對話方塊沒有背景,也不會觸發輕觸關閉。 - 請勿:將
click事件用於應在關閉「之前」發生的重要邏輯,請改為監聽close或cancel事件。
備用策略
必要:如果瀏覽器尚未支援 closedby,您必須使用下列指令碼,檢查點擊是否發生在對話方塊內容邊界外,為輕觸關閉功能實作備用方案:
const dialog = document.querySelector('dialog');
// Fallback for browsers without closedby support
if (!('closedBy' in HTMLDialogElement.prototype)) {
dialog.addEventListener('click', (event) => {
// 1. When clicking the backdrop, the event target is the dialog element itself.
// Ignore clicks where the target is a child element inside the dialog.
if (event.target !== dialog) return;
// 2. Check if the click coordinates fall within the dialog's content box.
// This distinguishes between a click on the backdrop vs a click on the dialog's background/padding.
const rect = dialog.getBoundingClientRect();
const isDialogContent = (
rect.top <= event.clientY &&
event.clientY <= rect.top + rect.height &&
rect.left <= event.clientX &&
event.clientX <= rect.left + rect.width
);
if (isDialogContent) return;
// 3. Since the click was outside the content area (on the backdrop), manually close the dialog.
dialog.close();
});
}