SELF-Treffen in Mannheim 2025

SELFHTML wird 30 Jahre alt! → Veranstaltungs-Ankündigung.

Infobox/modale Dialogfenster

Aus SELFHTML-Wiki
< Infobox(Weitergeleitet von HTML/Tutorials/dialog)
Wechseln zu: Navigation, Suche

Eine Dialog-Box ist ein neues Fenster, das sich über die Webseite legt, um eine Frage zu stellen, eine Eingabe abzufragen oder mehrere Optionen anzubieten. Dabei muss unterschieden werden:

  • Popover (aus dem letzten Kapitel) zeigen Benachrichtigungen oder zusätzliche Informationen. Der Nutzer kann sie beachten, aber auch normal weiterarbeiten.
  • Modale Dialogfenster erfordern wie alert() in JavaScript sofortige Aufmerksamkeit. Während sie geöffnet sind, ist die darunter liegende Webseite nicht aktiv und kann erst wiederverwendet werden, wenn die Dialog-Box geschlossen ist. Dies muss durch den Nutzer ausdrücklich bestätigt werden, was in der Regel durch Anklicken einer Schaltfläche innerhalb des Containers geschieht. In HTML5 wurde dafür das dialog-Element eingeführt, das seit 2022 von allen Browsern unterstützt wird.


dialog - ein Offenlegungs-Widget

Das dialog-Element ist wie ein div ein Container-Element für die in der Popup-Box enthaltenen Inhalte. Standardmäßig ist das Element nicht sichtbar.

dialog ohne JavaScript ansehen …
  <dialog open> <form action="#" method="dialog"> <label for="email">Bitte geben Sie Ihre Email-Adresse an: </label> <input id="email" type="email" /> <p><button id="Anmeldung">Anmelden</button> <button id="close-dialog">Abbrechen</button> </p> </form> </dialog>

Dialoge können Formulare enthalten. Entweder gewöhnliche, die zu einem GET oder POST-Request an den Server führen und die Seite neu laden, oder mittels <form method="dialog"> spezielle Dialog-Formulare.

Mit einem Klick auf einen Button im Formular wird der Dialog ganz ohne JavaScript geschlossen. Der Inhalt des value Attributs, das sich am geklickten Button befindet, wird dabei in die returnValue Eigenschaft des HTMLDialogElement-Objekts übertragen.[1]

Beachte: In diesem Beispiel ist die Dialog-Box nur durch das open-Attribut und CSS geöffnet und kann daher nicht - wie normalerweise - mit ESC geschlossen werden.

open-Attribut

Das boolesche Attribut open gibt an, ob der Dialog aktiv ist. Ist das Attribut vorhanden und enthält entweder den leeren String oder den String 'open', bedeutet dies, dass der Dialog aktiv ist. Wird das Attribut weggelassen, bedeutet dies, dass der Dialog inaktiv ist und vom Browser nicht angezeigt werden soll.

Ein Blick in den Seiteninspektor zeigt folgende Festlegung im Browser-Stylesheet:

CSS-Festlegungen für open ansehen …
/* Festlegung im Default-Stylesheet der Browser */
dialog:not([open]) {
  display: none;
}

/* Styling der geöffneten Popup-Box */
dialog[open] { 
  width: 20em; 
  background: #fffbf0; 
  border: thin solid #e7c157;
  margin: 5em auto;
}

Öffnen und Schließen

Ursprünglich war das dialog-Element dazu gedacht, im Zusammenspiel mit JavaScript geöffnet und auch wieder geschlossen zu werden. Das Dialog-Element besitzt sein eigenes DOM-Interface, das das Steuern von Ein-/Ausblenden und eventuellen Rückgabewerten ermöglicht.

Mittlerweile gibt es mehrere Möglichkeiten, Dialoge durch den Browser ohne JavaScript zu bedienen.

Öffnen mit showModal()

Für das Einblenden eines dialog-Elements mit JavaScript werden gleich zwei Optionen zur Verfügung gestellt:

dialog.show()
wird verwendet, um einen Dialog zu öffnen.
dialog.showModal()
öffnet den Dialog ebenfalls und macht ihn zusätzlich zum vordergründigsten Dialog der Anwendung. D.h. alle interaktiven Elemente der Webseite, außer den Kind-Elementen des modal geöffneten Dialogs, werden gesperrt. Es ist zulässig, weitere modale Dialoge zu öffnen. Jedes weitere Öffnen blockiert den bereits offenen modalen Dialog.
modales Dialogfenster ansehen …
document.getElementById("show-dialog").addEventListener("click", () => {
    document.getElementById("dialog").showModal();
});

document.getElementById("close-dialog").addEventListener("click", () => {
    document.getElementById("dialog").close();
});

Das dialog-Element ist ursprünglich geschlossen. Durch einen Klick auf den Button mit der id show-dialog wird das dialog-Element per JavaScript mit der showModal()-Methode geöffnet.

Damit die Dialog-Box die volle Aufmerksamkeit des Nutzers bekommt, befindet sich zwischen Dokument und der geöffneten Dialog-Box nun eine durchscheinende Schicht, die einen Zugriff auf das darunterliegende Dokument solange verhindert, bis die Dialog-Box geschlossen wird.

Die Schicht wird durch das Pseudoelement ::backdrop erzeugt, die den Seitenhintergrund mit einem durchscheinenden Overlay verdunkelt. Die dahinterliegende, eigentliche Webseite wird im Stack des Top-Layers versteckt und ist inaktiv.


Beispiel
dialog::backdrop { 
  background: hsl(201 50% 40% /.5) ;
}
Empfehlung: Ändere das JavaScript auf document.getElementById("dialog").show(); und beobachte die Unterschiede.

modal oder nichtmodal?

Wie in der Einführung bereits erwähnt, wird die Webseite bei einem modalen Dialogfenster inaktiv. Es wäre möglich, mehrere modale Dialogfenster zu öffnen, wobei das jeweils oberste die anderen ebenfalls inaktiv werden lässt.

Empfehlung: Bitte setze modale Dialogfenster nur sparsam ein!
Es gibt nichts Schlimmeres als auf der Suche nach Informationen erst ein Cookie-Banner wegklicken zu müssen, um dann nicht auf der Webseite selbst, sondern auf der Newsletter-Anmeldung hängenzubleiben.
Technisch ist dies möglich, aber für die Nutzer der Webseite ein Grund zum Abbruch.
Denke an die Benutzerfreundlichkeit (usability) deiner Webseite!

Öffnen mit command

Mit der oben vorgestellten Methode müssen Buttons neben dem showModal()-Aufruf noch entprechende aria-Attribute enthalten, damit das Öffnen des Dialogs barrierefrei wird.

Wäre es nicht einfacher, Buttons und Dialoge mit nativem Standardverhalten zu haben? Die open-ui.org hat analog zu popovertarget ein Öffnen und Schließen mit command und commandfor vorgeschlagen.[2][3]

Buttons mit command lösen - wenn sie angeklickt, berührt oder per Tastendruck ausgelöst werden - ein CommandEvent auf dem Element aus, auf das das commandfor-Attribut verweist:

Dialog ohne JavaScript, das command-Attribut ansehen …
<button command="show-modal" commandfor="my-dialog">
	Öffne Dialog-Box!
</button>

<dialog id="my-dialog" closedby="any">
	Ich bin eine Dialog-Box!
</dialog>

Die (ursprünglich versteckte) Dialog-Box kann durch den Button ohne JavaScript geöffnet werden. Dieser hat zwei Attribute:

Beachte: Dieses Beispiel funktioniert derzeit (Stand: März 2025) nur im Chrome Canary!

Neben show-modal sind auch weitere Aufrufe möglich:

Wert für command Aufruf entspricht popovertargetaction
show-popover showModal() -
show-popover showPopover() show
hide-popover hidePopover() hide
toggle-popover togglePopover() toggle

Langfristig sollen popovertarget und popovertargetaction durch command und commandfor ersetzt werden.

Diese Attribute sollen dann auch für select, audio und video eingesetzt werden können, wobei dies noch Änderungen unterworfen ist.

Schließen mit JavaScript

Eigentlich war es Standard, die Dialog-Box mit JavaScript zu schließen und sie dann auszuwerten:

dialog.close( [result] )
schließt einen Dialog und weist einen eventuellen Rückgabewert zu, der mit dem optionalen Parameter result übergeben werden kann.
dialog.returnValue
liefert den Rückgabewert, der zuvor mit dialog.close gesetzt wurde. Wurde dort kein Rückgabewert angegeben, wird stattdessen der leere String zurückgegeben.
Beispiel ansehen …
document.getElementById("show-dialog").addEventListener("click", () => {
    document.getElementById("dialog").showModal();
});

document.getElementById("close-dialog").addEventListener("click", () => {
    document.getElementById("dialog").close();
});

Die im dialog-Element enthaltenen Inhalte sind ursprünglich nicht sichtbar.

Erst ein Klick auf den Button mit der id show-dialog öffnet die Dialog-Box.

Ein Klick auf den close-dialogButton schließt das Dialog-Fenster wieder mit der close()-Methode.

Beachte: Wird ein Dialog nicht über den Aufruf der close-Methode geschlossen, sondern durch Drücken der ESC-Taste, behält die returnValue Eigenschaft ihren Wert.

light dismiss mit closedby

Im letzten Beispiel wurde kurz erwähnt, dass ESC eine Dialog-Box wieder schließt. Dies kennen Nutzer von anderen Programmen und Formularen und ist so erwartetes Verhalten. Ähnlich ist es mit einer light-dismiss-Funktionalität (leichtes Verlassen). Wenn man außerhalb des Dialog-Bereichs klickt, wird die Dialog-Box geschlossen.

Dies ist mit dem neuen closedby-Attribut möglich, wenn der Wert auf any gesetzt wird:

Dialog ohne JavaScript, das closedby-Attribut ansehen …
<button command="show-modal" commandfor="my-dialog">
	Öffne Dialog-Box!
</button>

<dialog id="my-dialog" closedby="any">
	Ich bin eine Dialog-Box!
</dialog>
Beachte: Dieses Beispiel funktioniert derzeit (Stand: März 2025) nur im Chrome Canary!

Manuel Matuzović hat die Möglichkeiten, eine Dialog-Box zu schließen, zusammengefasst:[4]

  1. Ein button in einem form method=dialog, wie im 1. Beispiel
  2. light dismiss mit closedby="any"
  3. die ESC-Taste, wenn man eine Tastatur hat
  4. Bei Android
    • mit einem Klick auf den back-Button.
    • mit TalkBack on Android mit der “back” Geste/ nach unten und rechts wischen (Swipen).

Anwendungsbeispiel

::backdrop und :modal - Animation mit CSS

Bei modalen Dialogen ist die Webseite inaktiv, bis die Dialogbox geschlossen ist. Um dies zu kennzeichnen, wurde bereits im oberen Beispiel der Hintergrund ausge„blaut“.

Man kann den Hintergrund, aber auch das Öffnen mit CSS gestalten und auch animieren. Dabei wird häufig auf das vermeintlich Bewährte zurückgegriffen: Das Setzen und Entfernen einer Klasse. Zumindest für das Öffnen kannst du aber auch die :modal-Pseudoklasse als Selektor verwenden:

animierter Dialog ansehen …
dialog:modal { 
  width: 20em; 
  background: #fffbf0; 
  border: thin solid #e7c157;
	margin: 5em auto;
	animation: show 1s ease normal;	
} 

@keyframes show{
    from {
        transform: translateY(-110%);
    }
    to {
        transform: translateY(0%);
    }
}

dialog::backdrop {
	background: hsl(201 50% 40% /.5);
	animation: none;
}
dialog[open]::backdrop {
	animation: show-backdrop 2s ease forwards;
}

@keyframes show-backdrop {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

Die Dialog-Box wird beim Öffnen mit einer CSS-Animation von oben eingeschoben. Dies funktioniert in allen Browsern.

Das ::backdrop-Pseudoelement wird ebenfalls sanft eingeblendet. Dies funktioniert (Stand: März 2025) in allen Browsern außer dem Firefox. In diesem wird der Hintergrund ohne die Animation dargestellt. Eine Alternative wäre ein seitenfüllender box-shadow anstelle des ::backdrop-Elements oder ein seitenfüllendes, halbtransparentes Dialog-Element, das mit einem kleineren Kind-Element arbeitet.

Ein animiertes Schließen funktioniert (noch) nicht mit reinem CSS. Eine Alternative stellt Geckotang vor, der beim Schließen eine Klasse .hide hinzufügt, die dialog und ::backdrop ausblendet und dann nach dem transitionend die Klasse wieder entfernt. [5][6]

Beachte, dass das ::backdrop-Pseudoelement von niemandem erbt, also keine in :root festgelegten custom properties übernimmt. Dies ist ärgerlich und wurde in der Spec angepasst, aber noch nicht von allen Browsern übernommen - geht aber bereits im Firefox![7]

Siehe auch

  • Bildwechsler
    • Lightbox
      • Thumbnail und Großansicht
      • Bildwechsler
  • Eigene modale Dialogfenster
    alert, confirm und prompt sind heute verpönt. Dieses Tutorial zeigt, wie man diese mit einem eigenen modalen Dialog nachbauen kann.
  • Kontextmenü
    • menu
    • contextmenu-Event


  • Zusammenfassung für längere Artikel

Weblinks

  1. WHATWG: dialog element
  2. open-ui.org: Invokers (Explainer)
  3. Invoker Commands: Additional Ways to Work With Dialog, Popover… and More? Daniel Schwarz on Nov 22, 2024 (css-tricks.com)
  4. Close requests, close watchers, and the dialog element Manuel Matuzović am 07.03.2025 (matuzo.at)
  5. <dialog> with animation by geckotang
  6. Dialogkomponente erstellen (und animieren) (web.dev)
  7. ::backdrop doesn’t inherit from anywhere (KilianValkhoff, 19 January 2023, )