Toast-Komponente erstellen

Ein grundlegender Überblick über das Erstellen einer adaptiven und barrierefreien Toast-Komponente.

In diesem Beitrag möchte ich erklären, wie man eine Toast-Komponente erstellt. Testen Sie die Demo ansehen.

<ph type="x-smartling-placeholder">
</ph>
Demo

Falls Sie Videos bevorzugen, finden Sie hier eine YouTube-Version dieses Beitrags:

Übersicht

Toasts sind nicht interaktive, passive und asynchrone Kurznachrichten für Nutzer. In der Regel werden sie als Oberflächen-Feedback-Muster verwendet, um die Nutzenden zu informieren. zu den Ergebnissen einer Aktion.

Interaktionen

Toasts unterscheiden sich von Benachrichtigungen, Warnungen und Aufforderungen, sie sind nicht interaktiv dass sie nicht geschlossen werden sollen. Benachrichtigungen sind für wichtigere Informationen, synchrone Nachrichten, erfordert Interaktionen oder Mitteilungen auf Systemebene (im Gegensatz zu Meldungen auf Seitenebene). Toasts sind passiver als andere Benachrichtigungsstrategien.

Markup

Die <output> -Element ist eine gute Wahl für den Toast, da es dem Bildschirm vorgelesen wird. Lesern. Korrekter HTML-Code bietet uns eine sichere Basis für die Optimierung mit JavaScript und und es gibt jede Menge JavaScript.

Toast

<output class="gui-toast">Item added to cart</output>

Es kann mehr inklusive indem Sie role="status" hinzufügen. Dies bietet eine ein Fallback, falls der Browser <output>-Elementen nicht die implizite Rolle gemäß der Spezifikation.

<output role="status" class="gui-toast">Item added to cart</output>

Ein Toast-Container

Es können mehrere Toasts gleichzeitig angezeigt werden. Um mehrere Toasts enthält, wird ein Container verwendet. Dieser Container verarbeitet auch die Position des Toasts auf dem Bildschirm.

<section class="gui-toast-group">
  <output role="status">Wizard Rose added to cart</output>
  <output role="status">Self Watering Pot added to cart</output>
</section>

Layouts

habe ich Toasts an die inset-block-end des Darstellungsbereichs entfernt. Wenn weitere Toasts hinzugefügt werden, werden sie über diesen Bildschirmrand gestapelt.

GUI-Container

Der Toast-Container übernimmt das gesamte Layout für die Präsentation von Toasts. Es ist fixed zum Darstellungsbereich und verwendet das logische Attribut Mit inset geben Sie an, Kanten zum Anpinnen sowie ein wenig padding von derselben Seite block-end.

.gui-toast-group {
  position: fixed;
  z-index: 1;
  inset-block-end: 0;
  inset-inline: 0;
  padding-block-end: 5vh;
}

Screenshot mit Overlay-Größe und Abstand der Entwicklertools über einem .gui-toast-Container-Element

Der Toast-Container positioniert sich nicht nur innerhalb des Darstellungsbereichs, sondern ist auch ein Rasterbehälter, mit denen Toasts ausgerichtet und verteilt werden können. Elemente werden als Gruppe mit justify-content und individuell zentriert mit justify-items. Etwas gap drauf geben, damit Toasts nicht anfassen.

.gui-toast-group {
  display: grid;
  justify-items: center;
  justify-content: center;
  gap: 1vh;
}

Screenshot mit CSS-Raster-Overlay auf der Pop-up-Gruppe, diesmal
und die Lücken zwischen
untergeordneten Toast-Elementen hervorheben.

Toast auf der Benutzeroberfläche

Ein einzelner Toast hat padding, einige weichere Ecken mit border-radius, und eine min()-Funktion, bei der Größenanpassung für Mobilgeräte und Desktop-Computer. Die responsive Größe im folgenden CSS-Code verhindert, dass Toasts mehr als 90% des Darstellungsbereichs ausdehnen 25ch

.gui-toast {
  max-inline-size: min(25ch, 90vw);
  padding-block: .5ch;
  padding-inline: 1ch;
  border-radius: 3px;
  font-size: 1rem;
}

Screenshot eines einzelnen „.gui-toast“-Elements mit Innenrand und Rahmen
Radius angezeigt wird.

Stile

Wenn Sie Layout und Positionierung festgelegt haben, können Sie CSS-Code hinzufügen, der die Anpassung an den Nutzer erleichtert. Einstellungen und Interaktionen.

Toast-Container

Toasts sind nicht interaktiv, das Antippen oder Wischen verarbeiten jedoch aktuell Zeigerereignisse. Verhindern, dass Toasts gestohlen werden mit folgendem CSS-Code erstellen:

.gui-toast-group {
  pointer-events: none;
}

Toast auf der Benutzeroberfläche

Verleihe den Toasts mit benutzerdefinierten Eigenschaften, HSL und bevorzugte Medienabfrage.

.gui-toast {
  --_bg-lightness: 90%;

  color: black;
  background: hsl(0 0% var(--_bg-lightness) / 90%);
}

@media (prefers-color-scheme: dark) {
  .gui-toast {
    color: white;
    --_bg-lightness: 20%;
  }
}

Animation

Ein neuer Toast sollte mit einer Animation angezeigt werden, sobald er auf dem Bildschirm erscheint. Um reduzierte Bewegungen zu berücksichtigen, setzen Sie translate-Werte auf 0, indem Sie Standardeinstellung. Der Bewegungswert wird jedoch auf eine Länge in einem Medien mit Bewegungspräferenz aktualisiert. Suchanfrage . Alle werden Animationen gezeigt, aber nur ein paar Nutzer sehen die Reise Entfernung.

Dies sind die Keyframes, die für die Toast-Animation verwendet werden. Das Preisvergleichsportal steuert die Eingang, Warten und Ausgang des Toasts in einer Animation.

@keyframes fade-in {
  from { opacity: 0 }
}

@keyframes fade-out {
  to { opacity: 0 }
}

@keyframes slide-in {
  from { transform: translateY(var(--_travel-distance, 10px)) }
}

Das Toast-Element richtet dann die Variablen ein und orchestriert die Keyframes.

.gui-toast {
  --_duration: 3s;
  --_travel-distance: 0;

  will-change: transform;
  animation: 
    fade-in .3s ease,
    slide-in .3s ease,
    fade-out .3s ease var(--_duration);
}

@media (prefers-reduced-motion: no-preference) {
  .gui-toast {
    --_travel-distance: 5vh;
  }
}

JavaScript

Wenn die Stile und den Screenreader für den barrierefreien HTML-Code bereit sind, ist JavaScript erforderlich, das Erstellen, Hinzufügen und Vernichten von Toasts nutzungsbasiert orchestrieren Ereignisse. Die Toast-Komponente sollte für Entwickler nur minimal und ganz einfach:

import Toast from './toast.js'

Toast('My first toast')

Toastgruppe und Toasts erstellen

Wenn das Toast-Modul aus JavaScript geladen wird, muss ein Toast-Container erstellt werden und fügen es der Seite hinzu. Ich habe das Element vor body hinzugefügt. Dadurch wird Es ist unwahrscheinlich, dass z-index Stapelprobleme auftreten, da sich der Container für längere Zeit über dem Container befindet. alle body-Elemente.

const init = () => {
  const node = document.createElement('section')
  node.classList.add('gui-toast-group')

  document.firstElementChild.insertBefore(node, document.body)
  return node
}

Screenshot der Toast-Gruppe zwischen den Tags „head“ und „body“.

Die Funktion init() wird intern im Modul aufgerufen, wodurch das Element als Toaster:

const Toaster = init()

Das Pop-up-HTML-Element wird mit der Funktion createToast() erstellt. Die Funktion benötigt Text für den Toast, erstellt ein <output>-Element, verziert mit einigen Klassen und Attributen, legt den Text fest und gibt den Knoten zurück.

const createToast = text => {
  const node = document.createElement('output')
  
  node.innerText = text
  node.classList.add('gui-toast')
  node.setAttribute('role', 'status')

  return node
}

Einen oder mehrere Toasts verwalten

JavaScript fügt dem Dokument jetzt einen Container für Toasts hinzu. Toasts hinzugefügt. Die Funktion addToast() orchestriert die Verarbeitung oder viele Toasts. Überprüfen Sie zunächst die Anzahl der Toasts und ob die Bewegung in Ordnung ist. Dann können Sie mit diesen Informationen den Toast anhängen Animation, sodass die anderen Toasts wie „Raum schaffen“ erscheinen auf den neuen Toast.

const addToast = toast => {
  const { matches:motionOK } = window.matchMedia(
    '(prefers-reduced-motion: no-preference)'
  )

  Toaster.children.length && motionOK
    ? flipToast(toast)
    : Toaster.appendChild(toast)
}

Beim ersten Toast fügt Toaster.appendChild(toast) einen Toast zum Seite, die die CSS-Animationen auslöst: "animieren", "3s" oder "animieren". flipToast() wird aufgerufen, wenn Toasts vorhanden sind. Dabei wird eine Technik verwendet, namens FLIP von Paul Lewis. Die Idee ist, die Differenz an den Positionen des Containers, also vor und nach dem Hinzufügen des neuen Toasts. Stellen Sie sich das vor, als würden Sie aufzeichnen, wo der Toaster ist, von der ursprünglichen bis zur tatsächlichen Position.

const flipToast = toast => {
  // FIRST
  const first = Toaster.offsetHeight

  // add new child to change container size
  Toaster.appendChild(toast)

  // LAST
  const last = Toaster.offsetHeight

  // INVERT
  const invert = last - first

  // PLAY
  const animation = Toaster.animate([
    { transform: `translateY(${invert}px)` },
    { transform: 'translateY(0)' }
  ], {
    duration: 150,
    easing: 'ease-out',
  })
}

CSS-Raster übernimmt das Heben des Layouts. Wenn ein neuer Toast hinzugefügt wird, platziert das Raster ihn am Anfang und platziert ihn an den anderen. Hinzu kommt, dass ein Web Animation ist zur Animation des Containers von der alten Position aus.

Zusammenführen des gesamten JavaScript-Codes

Beim Aufruf von Toast('my first toast') wird ein Toast erstellt und der Seite hinzugefügt (vielleicht ist sogar der Behälter animiert, um den neuen Toast unterzubringen), ein versprechen zurückgegeben und der erstellte Toast angesehen für Vervollständigung der CSS-Animation (die drei Keyframe-Animationen) für die Promise-Auflösung

const Toast = text => {
  let toast = createToast(text)
  addToast(toast)

  return new Promise(async (resolve, reject) => {
    await Promise.allSettled(
      toast.getAnimations().map(animation => 
        animation.finished
      )
    )
    Toaster.removeChild(toast)
    resolve() 
  })
}

Der verwirrende Teil dieses Codes ist die Funktion Promise.allSettled(). und toast.getAnimations()-Zuordnung. Da ich mehrere Keyframe-Animationen um sicher zu wissen, dass alle fertig sind, die von JavaScript angefordert werden, finished für die Erfüllung zu halten. allSettled macht das für uns funktioniert und löst sich als vollständig auf, sobald all seine Versprechen verfügbar sind. erfüllt wurden. Bei Verwendung von await Promise.allSettled() wird die nächste Zeile das Element problemlos entfernen und davon ausgehen kann, dass der Toast Lebenszyklus. Schließlich erfüllt der Anruf von resolve() das übergeordnete Toast-Versprechen. können Entwickler den Inhalt bereinigen oder andere Dinge erledigen, sobald der Toast angezeigt wurde.

export default Toast

Schließlich wird die Funktion Toast aus dem Modul exportiert, damit andere Skripts Daten importieren und verwenden.

Toast-Komponente verwenden

Um den Toast oder die Entwicklererfahrung des Toasts zu verwenden, importieren Sie den Toast und ruft sie mit einem Nachrichtenstring auf.

import Toast from './toast.js'

Toast('Wizard Rose added to cart')

Wenn die Entwicklerin oder der Entwickler etwas sauberer machen möchte, nachdem angezeigt wird, können sie asynchrone Warten.

import Toast from './toast.js'

async function example() {
  await Toast('Wizard Rose added to cart')
  console.log('toast finished')
}

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