Nowoczesne okna modalne często obsługują funkcję „lekkiego zamykania”, która umożliwia użytkownikom zamknięcie okna przez kliknięcie lub dotknięcie tła (obszaru poza oknem). Atrybut closedby umożliwia deklaratywne włączenie tego zachowania bez niestandardowego kodu JavaScript.
Implementacja
Aby włączyć tę funkcję:
- Dodaj
closedby="any"do elementu<dialog>. - Otwórz okno za pomocą
dialog.showModal().
Wartości atrybutów
any: umożliwia zamknięcie przez kliknięcie tła, „żądania zamknięcia” (klawiszEsc) i mechanizmy dla deweloperów (np.dialog.close()).closerequest: włącza tylko „żądania zamknięcia” i mechanizmy dla deweloperów. Jest to ustawienie domyślne w przypadku okien modalnych.none: okno mogą zamknąć tylko mechanizmy dewelopera.
Stylizowanie tła
Gdy okno jest otwierane jako modalne za pomocą showModal(), przeglądarka generuje pseudoelement ::backdrop. To tło obejmuje cały widoczny obszar i znajduje się bezpośrednio za oknem.
/* 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 */
}
Przykład
<!-- 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>
Ograniczenia i ułatwienia dostępu
- OBOWIĄZKOWO: użyj
closedby="any", aby deklaratywnie włączyć zamykanie przez kliknięcie poza elementem. - OBOWIĄZKOWO: zawsze otwieraj modalne okna dialogowe za pomocą
showModal(). Dzięki temu okno dialogowe znajduje się w górnej warstwie, zaznaczenie jest zablokowane, a klawiszEscjest obsługiwany. - DO: Use
aria-labelledbyoraria-labelto provide an accessible name for the dialog. - NIE: używaj elementu
closedbyw przypadku okien dialogowych, które nie są modalne (otwieranych za pomocąshow()), ponieważ nie mają one tła i nie wywołują zamknięcia po kliknięciu poza oknem. - NIE używaj zdarzenia
clickdo krytycznej logiki, która powinna nastąpić przed zamknięciem. Zamiast tego nasłuchuj zdarzeńcloselubcancel.
Strategie zastępcze
OBOWIĄZKOWO: w przypadku przeglądarek, które nie obsługują jeszcze atrybutu closedby, musisz wdrożyć zastępcze rozwiązanie do zamykania okna przez kliknięcie poza nim. Aby sprawdzić, czy kliknięcie nastąpiło poza granicami treści okna, użyj tego skryptu:
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();
});
}