Ein grundlegender Überblick darüber, wie du mit dem <dialog>
-Element farbadaptive, responsive und barrierefreie Mini- und Mega-Modals erstellen kannst.
In diesem Beitrag möchte ich meine Gedanken
zur Entwicklung von Farbanpassungs-,
reaktionsschnelle und barrierefreie Mini- und Mega-Modale mit dem <dialog>
-Element.
Testen Sie die Demo und sehen Sie sich die
Quelle.
Falls Sie Videos bevorzugen, finden Sie hier eine YouTube-Version dieses Beitrags:
Übersicht
Die
<dialog>
eignet sich hervorragend für In-Page-Kontextinformationen oder Aktionen. Überlegen Sie, wann die
Die Nutzererfahrung profitiert von einer Aktion auf derselben Seite statt einer mehrseitigen Aktion.
Aktion: z. B. weil das Formular klein ist oder die einzige vom
„Bestätigen“ oder „Abbrechen“ des Nutzers.
Das <dialog>
-Element ist seit Kurzem browserübergreifend stabil:
Unterstützte Browser
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
Bei dem Element fehlte ein paar Dinge. In diesem GUI Herausforderung: Ich füge die Entwicklererfahrung hinzu. zu erwartende Elemente: zusätzliche Termine, leichtes Schließen, benutzerdefinierte Animationen und eine Miniversion und den Mega-Typ aus.
Markup
Die wesentlichen Elemente eines <dialog>
-Elements sind bescheiden. Das Element wird
automatisch ausgeblendet und es sind Stile integriert, die Ihre Inhalte überlagern.
<dialog>
…
</dialog>
Wir können diese Baseline verbessern.
Üblicherweise hat ein Dialogelement ähnlich wie ein modales Element
sind austauschbar. Ich habe mir hier frei gelassen, das Dialogelement für
sowohl kleine Pop-ups (Mini- als auch Vollbild-Dialogfelder) (Mega). Von mir benannt
Mega- und Mini-Dialogfelder, wobei beide Dialoge leicht an verschiedene Anwendungsfälle angepasst wurden.
Ich habe ein modal-mode
-Attribut hinzugefügt, mit dem Sie den Typ angeben können:
<dialog id="MegaDialog" modal-mode="mega"></dialog>
<dialog id="MiniDialog" modal-mode="mini"></dialog>
Nicht immer, aber generell werden Dialogelemente verwendet, um einige
Interaktionsinformationen. Formulare in Dialogelementen sind wie gemacht
zusammen.
Es empfiehlt sich, den Inhalt des Dialogs
mit einem Formularelement zu umschließen,
JavaScript kann auf die vom Benutzer eingegebenen Daten zugreifen. Außerdem können Schaltflächen in den
ein Formular, das method="dialog"
verwendet, kann ein Dialogfeld ohne JavaScript schließen und
Daten.
<dialog id="MegaDialog" modal-mode="mega">
<form method="dialog">
…
<button value="cancel">Cancel</button>
<button value="confirm">Confirm</button>
</form>
</dialog>
Mega-Dialogfeld
Ein Mega-Dialogfeld hat drei Elemente innerhalb des Formulars:
<header>
,
<article>
,
und
<footer>
Diese dienen als semantische Container und Stilziele für die
Präsentation des Dialogfelds. Der Header betitelt das Dialogfenster und bietet einen Abschluss
Schaltfläche. Der Artikel bezieht sich auf Formulareingaben und -informationen. Die Fußzeile enthält
<menu>
von
Aktionsschaltflächen.
<dialog id="MegaDialog" modal-mode="mega">
<form method="dialog">
<header>
<h3>Dialog title</h3>
<button onclick="this.closest('dialog').close('close')"></button>
</header>
<article>...</article>
<footer>
<menu>
<button autofocus type="reset" onclick="this.closest('dialog').close('cancel')">Cancel</button>
<button type="submit" value="confirm">Confirm</button>
</menu>
</footer>
</form>
</dialog>
Die erste Menüschaltfläche enthält
autofocus
und einen onclick
-Inline-Event-Handler. Das Attribut autofocus
erhält
wenn das Dialogfeld geöffnet wird. Ich denke, es hat sich bewährt,
die Schaltfläche „Abbrechen“, nicht die Schaltfläche „Bestätigen“. So wird sichergestellt, dass die Bestätigung
bewusst und nicht versehentlich.
Mini-Dialogfeld
Das Mini-Dialogfeld ist dem Mega-Dialogfeld sehr ähnlich, es fehlt nur ein
<header>
-Element. Dadurch kann es kleiner und inline angezeigt werden.
<dialog id="MiniDialog" modal-mode="mini">
<form method="dialog">
<article>
<p>Are you sure you want to remove this user?</p>
</article>
<footer>
<menu>
<button autofocus type="reset" onclick="this.closest('dialog').close('cancel')">Cancel</button>
<button type="submit" value="confirm">Confirm</button>
</menu>
</footer>
</form>
</dialog>
Das Dialogelement bietet eine solide Grundlage für ein vollständiges Darstellungsbereichselement, das Daten und Nutzerinteraktionen sammeln. Diese Grundlagen können interessante und effektive Interaktionen auf Ihrer Website oder in Ihrer App.
Bedienungshilfen
Das Dialogelement verfügt über eine sehr gute integrierte Zugänglichkeit. Anstatt diese hinzuzufügen, wie ich es normalerweise tue, viele sind bereits verfügbar.
Fokus wird wiederhergestellt
So wie Sie es im Schritt Nebennavigation erstellen Komponente enthält, ist es wichtig, Beim Öffnen und Schließen liegt der Fokus auf dem jeweils relevanten Öffnen und Schließen. Schaltflächen. Wenn diese seitliche Navigationsleiste geöffnet wird, liegt der Fokus auf der Schließen-Schaltfläche. Wenn der Parameter wenn die Schließen-Schaltfläche gedrückt wird, wird wieder der Fokus auf die Schaltfläche gesetzt, über die sie geöffnet wurde.
Mit dem Dialogelement ist dies in das Standardverhalten integriert:
Wenn ihr den Dialog animieren möchtet, geht verloren. Im JavaScript-Bereich stelle ich ihn wieder her. Funktionalität.
Überfangfokus
Das Dialogelement verwaltet
inert
für Sie. Vor dem inert
wurde JavaScript verwendet, um den Fokus zu überwachen
sodass ein Element zurückbleibt, an dem es es abfängt und zurücksetzt.
Unterstützte Browser
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
Nach dem inert
können Teile des Dokuments „eingefroren“ sein so sehr, dass sie
nicht mehr fokussieren oder mit der Maus interaktiv sind. Anstelle von Fallen,
Fokus wird auf den einzigen interaktiven Teil des Dokuments gelenkt.
Element öffnen und automatisch fokussieren
Standardmäßig weist das Dialogelement dem ersten fokussierbaren Element den Fokus zu
im Dialogfeld-Markup ein. Wenn dies nicht das beste Element ist,
das Nutzende standardmäßig verwenden können,
Verwenden Sie das Attribut autofocus
. Wie bereits erwähnt, empfiehlt es sich,
, um dies auf die Schaltfläche „Abbrechen“ und nicht auf die Schaltfläche „Bestätigen“ zu setzen. Dadurch wird sichergestellt,
dass die Bestätigung absichtlich und nicht versehentlich erfolgt ist.
Wird mit der Escape-Taste geschlossen
Es ist wichtig, dieses potenziell störende Element einfach zu schließen. Glücklicherweise verarbeitet das Dialogelement die Escape-Taste für Sie, sodass Sie vor der Orchestrierungslast.
Stile
Es gibt eine einfache Möglichkeit, das Dialogelement zu gestalten, und einen harten Pfad. Die einfache
wird erreicht, indem die Anzeigeeigenschaft des Dialogfelds nicht geändert wird und
mit seinen Einschränkungen. benutzerdefinierte Animationen für
Öffnen und Schließen des Dialogfelds, wodurch das Attribut display
und mehr übernommen werden.
Stile mit offenen Requisiten
Um adaptive Farben und Einheitlichkeit des Designs insgesamt zu beschleunigen, habe ich CSS-Variablenbibliothek Open Props ein. In zusätzlich zu den bereitgestellten Variablen, importiere ich auch eine normalize und einige Schaltflächen, mit denen Sie Props öffnen. als optionale Importe zur Verfügung stellt. Diese Importe helfen mir dabei, Dialog und Demo, ohne dass viele Stile erforderlich sind, um es zu unterstützen und gut.
<dialog>
-Element gestalten
Inhaber der Property „display“
Durch das Standardverhalten zum Ein- und Ausblenden eines Dialogfeldelements wird die Anzeige umgeschaltet.
Property von block
in none
geändert. Das bedeutet leider, dass sie nicht animiert werden kann.
nach innen und außen, nur nach innen. Ich möchte eine Animation ein- und ausblenden. Der erste Schritt
eigene festlegen
display:
dialog {
display: grid;
}
Durch Ändern des Wertes der display-Eigenschaft und damit der Inhaberin, wie in den über dem CSS-Snippet müssen einige Stile verwaltet werden, User Experience zu gewährleisten. Der Standardstatus eines Dialogfelds geschlossen. Sie können diesen Status visuell darstellen und verhindern, dass das Dialogfeld Interaktionen mit den folgenden Stilen erhalten:
dialog:not([open]) {
pointer-events: none;
opacity: 0;
}
Jetzt ist das Dialogfeld unsichtbar und es kann nicht mit ihm interagiert werden, solange es nicht geöffnet ist. Später
Ich werde JavaScript hinzufügen, um das Attribut inert
im Dialogfeld zu verwalten
dass Nutzer, die eine Tastatur oder Screenreader verwenden, das ausgeblendete Dialogfeld nicht erreichen können.
Dem Dialogfeld ein adaptives Farbdesign geben
Während color-scheme
Ihr Dokument in einem vom Browser bereitgestellten
adaptives Farbschema an die Einstellungen des hellen und
dunklen Systems angepasst wird.
das Dialogelement. Open Props bietet einige Oberflächen
Farben, die sich automatisch an die
hellen und dunklen Systemeinstellungen, ähnlich wie bei der Verwendung von color-scheme
. Diese
sind ideal, um Ebenen in einem Design zu erstellen, und ich liebe es, Farben zu verwenden,
unterstreichen diese Darstellung von Ebenenoberflächen. Die Hintergrundfarbe ist
var(--surface-1)
; Um auf diesen Layer zu setzen, verwenden Sie var(--surface-2)
:
dialog {
…
background: var(--surface-2);
color: var(--text-1);
}
@media (prefers-color-scheme: dark) {
dialog {
border-block-start: var(--border-size-1) solid var(--surface-3);
}
}
Für untergeordnete Elemente, z. B. die Kopfzeile, werden später weitere adaptive Farben hinzugefügt. und in der Fußzeile. Ich betrachte sie als zusätzlichen Dialogelement, aber sehr wichtig für ein überzeugendes und schön gestaltetes Dialogdesign.
Größe des responsiven Dialogfelds anpassen
Die Größe des Dialogfelds wird standardmäßig an seinen Inhalt delegiert, was in der Regel
super. Mein Ziel ist es, die Reichweite
max-inline-size
auf eine lesbare Größe (--size-content-3
= 60ch
) oder 90% der Breite des Darstellungsbereichs. Dieses
sorgt dafür, dass das Dialogfeld auf einem Mobilgerät nicht randlos erscheint
breit auf einem Desktop-Bildschirm,
der schwer lesbar ist. Dann füge ich eine
max-block-size
damit das Dialogfeld die Höhe der Seite nicht überschreitet. Das bedeutet auch, dass wir
muss angegeben werden, wo sich der scrollbare Bereich des Dialogfelds befindet.
Dialogelement.
dialog {
…
max-inline-size: min(90vw, var(--size-content-3));
max-block-size: min(80vh, 100%);
max-block-size: min(80dvb, 100%);
overflow: hidden;
}
Siehst du, dass ich max-block-size
zweimal habe? Im ersten Beispiel wird 80vh
verwendet, ein physischer
Darstellungsbereich-Einheit. Ich möchte, dass der Dialog
innerhalb eines relativen Ablaufs bleibt,
für internationale Nutzer. Daher verwende ich die logische, neuere und nur teilweise
unterstützte dvb
-Einheit in der zweiten Deklaration, wenn sie stabiler wird.
Positionierung des Mega-Dialogfelds
Um die Positionierung eines Dialogelements zu erleichtern, empfiehlt es sich, seine beiden Teilen: den Vollbildhintergrund und den Dialogcontainer. Der Hintergrund muss decken Sie alles ab und fügen einen Schattierungseffekt hinzu, um zu verdeutlichen, dass dieses Dialogfeld und der Inhalt dahinter ist unzugänglich. Der Dialogcontainer kann über diesem Hintergrund zentrieren und die Form annehmen, die der Inhalt erfordert.
Mit den folgenden Stilen wird das Dialogelement am Fenster fixiert, sodass es jeweils
und margin: auto
verwendet, um den Inhalt zu zentrieren:
dialog {
…
margin: auto;
padding: 0;
position: fixed;
inset: 0;
z-index: var(--layer-important);
}
Stile des Mega-Dialogfelds für Mobilgeräte
Bei kleinen Darstellungsbereichen gestalte ich dieses Vollbild-Modaldialogfeld etwas anders. Ich
den unteren Rand auf 0
festlegen, wodurch sich der Inhalt des Dialogfelds am Ende des Dialogfelds befindet.
Darstellungsbereich. Mit ein paar Stilanpassungen kann ich das Dialogfeld
Aktionsblatt näher an den Daumen der Nutzenden:
@media (max-width: 768px) {
dialog[modal-mode="mega"] {
margin-block-end: 0;
border-end-end-radius: 0;
border-end-start-radius: 0;
}
}
Mini-Dialogpositionierung
In einem größeren Darstellungsbereich, z. B. auf einem Desktop-Computer, platziere ich die Mini-Dialogfelder über das Element, das sie aufgerufen hat. Dazu benötige ich JavaScript. Sie finden die Technik, die ich verwende hier, aber ich glaube, dass dies den Rahmen dieses Artikels sprengen würde. Ohne JavaScript Mini-Dialogfeld wird genau wie ein Mega-Dialog in der Mitte des Bildschirms angezeigt.
Mach es knackig
Verleihen Sie dem Dialog auch etwas Flair, damit er wie eine weiche Oberfläche aussieht, die weit weg sitzt. oberhalb der Seite platzieren. Diese wird durch Abrunden der Ecken des Dialogfelds erreicht. Die Tiefe wird mit einem der sorgfältig gefertigten Schatten von Open Props erreicht. Ausstattung:
dialog {
…
border-radius: var(--radius-3);
box-shadow: var(--shadow-6);
}
Hintergrund-Pseudoelement anpassen
Ich entschied mich, ganz leicht im Hintergrund zu arbeiten, nur einen Weichzeichnereffekt
backdrop-filter
zum Mega-Dialogfeld hinzu:
Unterstützte Browser
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
dialog[modal-mode="mega"]::backdrop {
backdrop-filter: blur(25px);
}
Ich habe mich auch für eine Umstellung auf backdrop-filter
entschieden, da ich hoffe, dass Browser
wird ein Wechsel des Hintergrundelements möglich sein:
dialog::backdrop {
transition: backdrop-filter .5s ease;
}
Stile für Extras
Ich nenne diesen Bereich "Extras". Es hat mehr mit meinem Dialogelement zu tun als das Dialogelement im Allgemeinen.
Begrenzungen scrollen
Wenn das Dialogfeld angezeigt wird, können Nutzende die Seite dahinter scrollen, Das möchte ich nicht:
Normalerweise
overscroll-behavior
wäre meine übliche Lösung, aber entsprechend dem
Spezifikation
hat das keine Auswirkungen auf das Dialogfeld, da es sich nicht um einen Scroll-Port handelt, sondern um
damit nichts verhindert werden kann. Ich könnte mithilfe von JavaScript nach
die neuen Ereignisse aus diesem Leitfaden, wie z. B. „geschlossen“, und "Geöffnet" und wechseln Sie
overflow: hidden
für das Dokument oder ich könnte warten, bis :has()
stabil ist in
alle Browser:
Unterstützte Browser
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
html:has(dialog[open][modal-mode="mega"]) {
overflow: hidden;
}
Wenn jetzt ein Mega-Dialogfeld geöffnet ist, enthält das HTML-Dokument overflow: hidden
.
Das <form>
-Layout
Sie ist nicht nur ein sehr wichtiges Element,
um Interaktionen zu erfassen,
von den Nutzenden erhalten, verwende ich sie hier, um die Kopf-, Fußzeile und
Artikel-Elementen enthalten. Mit diesem Layout möchte ich das untergeordnete Artikelelement als
scrollen können. Das erreiche ich mit
grid-template-rows
Das Artikelelement erhält den Wert 1fr
und das Formular selbst hat das gleiche Maximum
"height" als Dialogelement festlegen. Das Festlegen dieser festen Höhe und der festen Zeilengröße
kann das Artikelelement fixiert werden und scrollt, wenn es überläuft:
dialog > form {
display: grid;
grid-template-rows: auto 1fr auto;
align-items: start;
max-block-size: 80vh;
max-block-size: 80dvb;
}
Stil des Dialogfelds <header>
festlegen
Mit diesem Element geben Sie einen Titel für den Inhalt und das Angebot des Dialogs an. einfach zu findende Schließen-Schaltfläche. Außerdem erhält er eine Oberflächenfarbe, hinter dem Inhalt des Dialogartikels. Diese Anforderungen führen zu einer Flexbox Behälter, vertikal ausgerichtete Elemente mit Abstand zu ihren Kanten sowie einige Abstand und Lücken, damit die Titel- und Schließen-Schaltflächen mehr Platz haben:
dialog > form > header {
display: flex;
gap: var(--size-3);
justify-content: space-between;
align-items: flex-start;
background: var(--surface-2);
padding-block: var(--size-3);
padding-inline: var(--size-5);
}
@media (prefers-color-scheme: dark) {
dialog > form > header {
background: var(--surface-1);
}
}
Stil für die Schließen-Schaltfläche in der Kopfzeile festlegen
Da in der Demo die Schaltflächen "Props öffnen" verwendet werden, ist die Schaltfläche "Schließen" angepasst. in eine runde Symbol-Schaltfläche in der Mitte:
dialog > form > header > button {
border-radius: var(--radius-round);
padding: .75ch;
aspect-ratio: 1;
flex-shrink: 0;
place-items: center;
stroke: currentColor;
stroke-width: 3px;
}
Stil des Dialogfelds <article>
festlegen
Das Artikelelement hat in diesem Dialogfeld eine besondere Rolle: Es ist ein Leerzeichen, bei einem langen oder langen Dialogfeld gescrollt werden kann.
Um dies zu erreichen, hat das übergeordnete Formularelement einige Höchstwerte für
die Einschränkungen für dieses Artikelelement vorgeben, die erreicht werden können, wenn es
zu hoch. Legen Sie overflow-y: auto
so fest, dass Bildlaufleisten nur bei Bedarf angezeigt werden.
mit overscroll-behavior: contain
Scrollen darin enthalten, und der Rest
sind benutzerdefinierte Präsentationsstile:
dialog > form > article {
overflow-y: auto;
max-block-size: 100%; /* safari */
overscroll-behavior-y: contain;
display: grid;
justify-items: flex-start;
gap: var(--size-3);
box-shadow: var(--shadow-2);
z-index: var(--layer-1);
padding-inline: var(--size-5);
padding-block: var(--size-3);
}
@media (prefers-color-scheme: light) {
dialog > form > article {
background: var(--surface-1);
}
}
Stil des Dialogfelds <footer>
festlegen
Die Rolle der Fußzeile besteht darin, Menüs mit Aktionsschaltflächen zu enthalten. Flexbox wird verwendet, um Richten Sie den Inhalt am Ende der Inline-Achse der Fußzeile aus. um den Tasten etwas Platz zu geben.
dialog > form > footer {
background: var(--surface-2);
display: flex;
flex-wrap: wrap;
gap: var(--size-3);
justify-content: space-between;
align-items: flex-start;
padding-inline: var(--size-5);
padding-block: var(--size-3);
}
@media (prefers-color-scheme: dark) {
dialog > form > footer {
background: var(--surface-1);
}
}
Menü für die Fußzeile des Dialogfelds gestalten
Die menu
-Element wird die Aktionsschaltflächen für das Dialogfeld enthalten. Dabei wird ein Wrapping
Flexbox-Layout mit gap
, um Platz zwischen den Schaltflächen zu schaffen. Menüelemente
haben einen Innenrand, z. B. <ul>
. Ich entferne auch diesen Stil,
da ich ihn nicht benötige.
dialog > form > footer > menu {
display: flex;
flex-wrap: wrap;
gap: var(--size-3);
padding-inline-start: 0;
}
dialog > form > footer > menu:only-child {
margin-inline-start: auto;
}
Animation
Dialogfeldelemente sind häufig animiert, da sie das Fenster betreten und verlassen. Durch unterstützende Bewegung an den Ein- und Ausgang von Dialogfeldern können Nutzende sich im Fluss zu orientieren.
Normalerweise kann das Dialogelement nur inner- und nicht außen animiert werden. Das liegt daran,
Der Browser schaltet die Eigenschaft display
für das Element um. Die Anleitung
„Rasteranzeige“ und nie auf „Keine“. Dadurch können Sie
dass sie immer wieder
animieren können.
Open Props enthält viele Keyframes. Animationen erstellt und so gestaltet, Orchestrierung einfach und gut lesbar ist. Hier sehen Sie die Ziele für Animationen Ansatz:
- Reduzierte Bewegung ist der Standardübergang, ein einfaches Ein- und Ausblenden der Deckkraft.
- Wenn die Bewegung in Ordnung ist, werden Folien- und Skalierungsanimationen hinzugefügt.
- Das responsive mobile Layout für das Mega-Dialogfeld wird so angepasst, dass es herauszoomt.
Sicherer und sinnvoller Standardwechsel
Obwohl offene Props Keyframes zum Ein- und Ausblenden bieten, ziehe ich diese
standardmäßig aktiviert, wobei Keyframe-Animationen
potenzielle Upgrades. Die Sichtbarkeit des Dialogfelds
haben wir bereits mit
Deckkraft, wobei 1
oder 0
je nach [open]
-Attribut orchestriert wird. Bis
zwischen 0 und 100 Prozent liegt, teilen Sie dem Browser mit, wie lange
Gewünschtes Easing:
dialog {
transition: opacity .5s var(--ease-3);
}
Dem Übergang Bewegung hinzufügen
Wenn der Nutzer kein Problem mit Bewegungen hat, sollten sich sowohl das Mega- als auch das Mini-Dialogfeld verschieben.
als Eingang und hochskaliert als Ausstieg. Dies erreichen Sie mit dem
prefers-reduced-motion
-Medienabfrage und einige offene Props:
@media (prefers-reduced-motion: no-preference) {
dialog {
animation: var(--animation-scale-down) forwards;
animation-timing-function: var(--ease-squish-3);
}
dialog[open] {
animation: var(--animation-slide-in-up) forwards;
}
}
Exit-Animation für Mobilgeräte anpassen
Im Abschnitt „Stile“ wurde der Stil des Mega-Dialogs bereits für Mobilgeräte angepasst. wie ein Blatt Papier, als ob ein Blatt Papier vom unteren Displayrand nach oben und ist immer noch unten angebracht. Die Waage die Exit-Animation nicht gut in das neue Design passt, und wir können es mit Medienabfragen und offene Props:
@media (prefers-reduced-motion: no-preference) and @media (max-width: 768px) {
dialog[modal-mode="mega"] {
animation: var(--animation-slide-out-down) forwards;
animation-timing-function: var(--ease-squish-2);
}
}
JavaScript
Mit JavaScript müssen Sie einige Dinge hinzufügen:
// dialog.js
export default async function (dialog) {
// add light dismiss
// add closing and closed events
// add opening and opened events
// add removed event
// removing loading attribute
}
Diese Ergänzungen ergeben sich aus dem Wunsch, Licht auszuschalten (durch Klicken auf das Dialogfeld Bilderrahmen), Animationen und einige zusätzliche Ereignisse, um das der Formulardaten.
Licht beim Hinzufügen ausschalten
Diese Aufgabe ist unkompliziert und eine tolle Ergänzung für ein Dialogelement,
animiert sein. Die Interaktion erfolgt durch Beobachten der Klicks im Dialogfeld
und die Nutzung von Ereignissen
sprudelnd
um zu beurteilen, auf was geklickt wurde.
close()
wenn es das oberste Element ist:
export default async function (dialog) {
dialog.addEventListener('click', lightDismiss)
}
const lightDismiss = ({target:dialog}) => {
if (dialog.nodeName === 'DIALOG')
dialog.close('dismiss')
}
Beachten Sie dialog.close('dismiss')
. Das Ereignis wird aufgerufen und ein String wird bereitgestellt.
Dieser String kann von anderem JavaScript abgerufen werden, um zu ermitteln, wie der
Dialogfeld wurde geschlossen. Sie werden feststellen, dass ich bei jedem Aufruf
die Funktion über verschiedene Schaltflächen, um für meine Anwendung
die Interaktion der Nutzenden.
Schließende und geschlossene Ereignisse hinzufügen
Das Dialogelement hat ein Schließen-Ereignis: Es wird sofort ausgelöst, wenn der
Dialog close()
aufgerufen. Da wir dieses Element animieren,
Es ist toll, dass vor und nach der Animation Termine vorhanden sind.
oder das Dialogformular zurücksetzen. Hier verwalte ich das Hinzufügen der
Attribut inert
im geschlossenen Dialogfeld und verwende es in der Demo, um es zu ändern
in der Avatarliste, wenn der Nutzer ein neues Bild eingereicht hat.
Erstellen Sie dazu zwei neue Ereignisse mit den Namen closing
und closed
. Dann
Warten Sie auf das integrierte
Schließen-Ereignis im Dialogfeld. Legen Sie dann das Dialogfeld
inert
und senden das closing
-Ereignis. Als Nächstes müssen Sie warten,
der Animationen und Übergänge, um die Ausführung im Dialogfeld abzuschließen,
closed
-Ereignis.
const dialogClosingEvent = new Event('closing')
const dialogClosedEvent = new Event('closed')
export default async function (dialog) {
…
dialog.addEventListener('close', dialogClose)
}
const dialogClose = async ({target:dialog}) => {
dialog.setAttribute('inert', '')
dialog.dispatchEvent(dialogClosingEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogClosedEvent)
}
const animationsComplete = element =>
Promise.allSettled(
element.getAnimations().map(animation =>
animation.finished))
Die Funktion animationsComplete
, die auch im Modul Toast erstellen
Komponente, gibt ein Versprechen basierend auf dem
die Fertigstellung der Animation
und der Übergang. Aus diesem Grund dialogClose
ist ein asynchrones
Funktion;
kann es dann
await
das Versprechen zurückgegeben und
selbstbewusst auf das Closed-Ereignis übergegangen werden.
Öffnende und geöffnete Ereignisse hinzufügen
Diese Ereignisse lassen sich nicht so einfach hinzufügen, da das integrierte Dialogelement die ein offenes Ereignis wie bei einem Schließen bereitstellen. Ich nutze MutationObserver um Einblicke in die sich ändernden Attribute des Dialogfelds zu erhalten. In diesem Beobachter Ich achte auf Änderungen am offenen Attribut und verwalte die benutzerdefinierten Ereignisse entsprechend anpassen.
Ähnlich wie bei den Abschluss- und Geschlossener-Ereignissen erstellen Sie zwei neue Ereignisse,
namens opening
und opened
. Wo zuvor auf das Schließen des Dialogfelds gewartet wurde
-Ereignis, verwenden Sie dieses Mal einen erstellten Mutationsbeobachter, um die
Attribute.
…
const dialogOpeningEvent = new Event('opening')
const dialogOpenedEvent = new Event('opened')
export default async function (dialog) {
…
dialogAttrObserver.observe(dialog, {
attributes: true,
})
}
const dialogAttrObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(async mutation => {
if (mutation.attributeName === 'open') {
const dialog = mutation.target
const isOpen = dialog.hasAttribute('open')
if (!isOpen) return
dialog.removeAttribute('inert')
// set focus
const focusTarget = dialog.querySelector('[autofocus]')
focusTarget
? focusTarget.focus()
: dialog.querySelector('button').focus()
dialog.dispatchEvent(dialogOpeningEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogOpenedEvent)
}
})
})
Die Mutationsobserver-Callback-Funktion wird aufgerufen, wenn das Dialogfeld
geändert werden und die Liste der Änderungen als Array bereitstellen. Überarbeiten
Das Attribut ändert sich und attributeName
muss offen sein. Als Nächstes aktivieren Sie
ob das Element das Attribut hat oder nicht: Dies gibt an, ob das Dialogfeld
ist offen geworden. Wenn es geöffnet wurde, entfernen Sie das Attribut inert
und setzen Sie den Fokus
entweder einem Element hinzu, das
autofocus
oder das erste button
-Element im Dialogfeld. Ähnlich wie bei der abschließenden
und Closed, sofort das Eröffnungsereignis auslösen, auf die Animationen warten,
um den Vorgang abzuschließen, und
senden Sie dann das Ereignis "open".
Entfernte Termine hinzufügen
In Single-Page-Anwendungen werden Dialogfelder häufig basierend auf Routen hinzugefügt und entfernt. oder andere Anwendungsanforderungen und -status. Es kann nützlich sein, Ereignisse oder wenn ein Dialogfeld entfernt wird.
Sie können dies mit einem anderen Mutationsbeobachter erreichen. Dieses Mal statt der Beobachtung von Attributen eines dialogelements und achten Sie darauf, dass Dialogelemente entfernt werden.
…
const dialogRemovedEvent = new Event('removed')
export default async function (dialog) {
…
dialogDeleteObserver.observe(document.body, {
attributes: false,
subtree: false,
childList: true,
})
}
const dialogDeleteObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(mutation => {
mutation.removedNodes.forEach(removedNode => {
if (removedNode.nodeName === 'DIALOG') {
removedNode.removeEventListener('click', lightDismiss)
removedNode.removeEventListener('close', dialogClose)
removedNode.dispatchEvent(dialogRemovedEvent)
}
})
})
})
Der Mutationsobserver-Callback wird aufgerufen, wenn untergeordnete Elemente hinzugefügt oder entfernt werden
aus dem Textkörper des Dokuments. Die beobachteten spezifischen Mutationen
removedNodes
mit den
nodeName
von
ein Dialogfeld. Wenn ein Dialogfeld entfernt wurde, werden die Ereignisse vom Typ „Klick“ und „Schließen“ in
freigeben, um Arbeitsspeicher freizugeben.
Das benutzerdefinierte Ereignis "Entfernt" wird gesendet.
Ladeattribut wird entfernt
Um zu verhindern, dass die Dialoganimation ihre Exit-Animation wiedergibt, wenn sie zu der Seite oder beim Seitenaufbau wird dem Dialogfeld ein Ladeattribut hinzugefügt. Die das folgende Skript wartet, bis die Dialoganimationen fertig sind, und entfernt das Attribut. Der Dialog kann jetzt ein- und ausgeblendet werden. eine ansonsten ablenkende Animation effektiv verborgen.
export default async function (dialog) {
…
await animationsComplete(dialog)
dialog.removeAttribute('loading')
}
Weitere Informationen zum Problem, wie Keyframe-Animationen beim Seitenaufbau verhindert werden hier.
Alles zusammen
Hier sehen Sie den vollständigen Text von dialog.js
, nachdem wir die einzelnen Abschnitte erklärt haben.
einzeln:
// custom events to be added to <dialog>
const dialogClosingEvent = new Event('closing')
const dialogClosedEvent = new Event('closed')
const dialogOpeningEvent = new Event('opening')
const dialogOpenedEvent = new Event('opened')
const dialogRemovedEvent = new Event('removed')
// track opening
const dialogAttrObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(async mutation => {
if (mutation.attributeName === 'open') {
const dialog = mutation.target
const isOpen = dialog.hasAttribute('open')
if (!isOpen) return
dialog.removeAttribute('inert')
// set focus
const focusTarget = dialog.querySelector('[autofocus]')
focusTarget
? focusTarget.focus()
: dialog.querySelector('button').focus()
dialog.dispatchEvent(dialogOpeningEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogOpenedEvent)
}
})
})
// track deletion
const dialogDeleteObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(mutation => {
mutation.removedNodes.forEach(removedNode => {
if (removedNode.nodeName === 'DIALOG') {
removedNode.removeEventListener('click', lightDismiss)
removedNode.removeEventListener('close', dialogClose)
removedNode.dispatchEvent(dialogRemovedEvent)
}
})
})
})
// wait for all dialog animations to complete their promises
const animationsComplete = element =>
Promise.allSettled(
element.getAnimations().map(animation =>
animation.finished))
// click outside the dialog handler
const lightDismiss = ({target:dialog}) => {
if (dialog.nodeName === 'DIALOG')
dialog.close('dismiss')
}
const dialogClose = async ({target:dialog}) => {
dialog.setAttribute('inert', '')
dialog.dispatchEvent(dialogClosingEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogClosedEvent)
}
// page load dialogs setup
export default async function (dialog) {
dialog.addEventListener('click', lightDismiss)
dialog.addEventListener('close', dialogClose)
dialogAttrObserver.observe(dialog, {
attributes: true,
})
dialogDeleteObserver.observe(document.body, {
attributes: false,
subtree: false,
childList: true,
})
// remove loading attribute
// prevent page load @keyframes playing
await animationsComplete(dialog)
dialog.removeAttribute('loading')
}
Modul dialog.js
verwenden
Die aus dem Modul exportierte Funktion erwartet, aufgerufen zu werden und ein Dialogfeld zu übergeben. -Element das diese neuen Ereignisse und Funktionen hinzufügen möchte:
import GuiDialog from './dialog.js'
const MegaDialog = document.querySelector('#MegaDialog')
const MiniDialog = document.querySelector('#MiniDialog')
GuiDialog(MegaDialog)
GuiDialog(MiniDialog)
Jetzt werden die beiden Dialogfelder mit leichtem Schließen, Animation Fehlerbehebungen und weitere Ereignisse, mit denen Sie arbeiten können.
Neue benutzerdefinierte Ereignisse überwachen
Jedes aktualisierte Dialogelement kann jetzt auf fünf neue Ereignisse warten:
MegaDialog.addEventListener('closing', dialogClosing)
MegaDialog.addEventListener('closed', dialogClosed)
MegaDialog.addEventListener('opening', dialogOpening)
MegaDialog.addEventListener('opened', dialogOpened)
MegaDialog.addEventListener('removed', dialogRemoved)
Hier zwei Beispiele für die Verarbeitung dieser Ereignisse:
const dialogOpening = ({target:dialog}) => {
console.log('Dialog opening', dialog)
}
const dialogClosed = ({target:dialog}) => {
console.log('Dialog closed', dialog)
console.info('Dialog user action:', dialog.returnValue)
if (dialog.returnValue === 'confirm') {
// do stuff with the form values
const dialogFormData = new FormData(dialog.querySelector('form'))
console.info('Dialog form data', Object.fromEntries(dialogFormData.entries()))
// then reset the form
dialog.querySelector('form')?.reset()
}
}
In der Demo, die ich mit dem Dialogelement erstellt habe, um der Liste ein neues Avatar-Element hinzuzufügen. Das Timing ist in dass das Dialogfeld seine Exit-Animation abgeschlossen hat und dass einige Skripts im neuen Avatar. Dank der neuen Ereignisse lässt sich die Nutzererfahrung flüssiger sein.
Beachten Sie dialog.returnValue
: Dies enthält den String zum Schließen, der übergeben wird, wenn die
Dialog close()
-Ereignis wird aufgerufen. Es ist beim dialogClosed
-Ereignis wichtig,
ob das Dialogfeld geschlossen, abgebrochen oder bestätigt wurde. Wenn das der Fall ist,
erfasst dann die Formularwerte und setzt das Formular zurück. Das Zurücksetzen ist nützlich,
dass das Dialogfeld leer ist, wenn es erneut angezeigt wird.
Fazit
Jetzt, wo du weißt, wie ich es gemacht habe, wie würdest du... ‽ 🙂
Lassen Sie uns unsere Herangehensweisen diversifizieren und alle Möglichkeiten kennenlernen, wie wir das Web entwickeln können.
Erstelle eine Demo, twittere mir Links und ich füge sie hinzu im Abschnitt „Community-Remixe“ weiter unten.
Community-Remixe
- @GrimLink mit einem 3-in-1-Gerät Dialogfeld.
- @mikemai2awesome mit einem schönen
Remixe, die den
display
. - @geoffrich_ mit Svelte und schön Lackierung von Svelte FLIP
Ressourcen
- Quellcode auf GitHub
- Doodle-Avatare