Einstellungen-Komponente erstellen

Eine grundlegende Übersicht darüber, wie Sie eine Einstellungen-Komponente mit Schiebereglern und Kästchen erstellen.

In diesem Beitrag möchte ich meine Überlegungen zum Erstellen einer Einstellungs-Komponente für das Web teilen, die responsiv ist, mehrere Geräteeingaben unterstützt und in allen Browsern funktioniert. Demo ansehen

Demo

Wenn Sie sich lieber ein Video ansehen oder eine Vorschau der Benutzeroberfläche sehen möchten, finden Sie hier eine kurze Anleitung auf YouTube:

Übersicht

Die Aspekte dieser Komponente sind in die folgenden Abschnitte unterteilt:

  1. Layouts
  2. Farbe
  3. Benutzerdefinierter Bereich
  4. Benutzerdefinierte Kästcheneingabe
  5. Barrierefreiheit
  6. JavaScript

Layouts

Dies ist die erste GUI Challenge-Demo, die ausschließlich CSS-Grid verwendet. Hier sehen Sie die einzelnen Grids, die mit den Chrome-Entwicklertools für Grid hervorgehoben wurden:

Bunte Umrisse und Overlays für den Abstand zwischen den Feldern, die alle Felder des Einstellungs-Layouts zeigen

Nur für Lücke

Das häufigste Layout:

foo {
  display: grid;
  gap: var(--something);
}

Ich nenne dieses Layout „nur für Lücken“, weil es nur das Raster verwendet, um Lücken zwischen Blöcken hinzuzufügen.

Fünf Layouts verwenden diese Strategie. Hier sehen Sie alle:

Vertikale Rasterlayouts mit Umrisslinien und ausgefüllten Lücken

Das fieldset-Element, das jede Eingabegruppe (.fieldset-item) enthält, verwendet gap: 1px, um die dünnen Linien zwischen den Elementen zu erstellen. Keine komplizierte Lösung für die Ränder erforderlich.

Gefüllte Lücke
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Rahmentrick
.grid {
  display: grid;

  & > .fieldset-item {
    background: var(--bg-surface-2);

    &:not(:last-child) {
      border-bottom: 1px solid var(--bg-surface-1);
    }
  }
}

Natürlicher Rasterumbruch

Das komplexeste Layout war das Makrolayout, das logische Layoutsystem zwischen <main> und <form>.

Umbrechen von Inhalten zentrieren

Sowohl Flexbox als auch Grid bieten Möglichkeiten zum align-items oder align-content. Bei umgebrochenen Elementen wird der verfügbare Platz durch die content-Layoutausrichtungen gleichmäßig auf die untergeordneten Elemente verteilt.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
}

Das Hauptelement verwendet die place-content: center-Kurzschreibweise für die Ausrichtung, damit die untergeordneten Elemente sowohl in ein- als auch in zweispaltigen Layouts vertikal und horizontal zentriert werden.

Im Video oben sehen Sie, wie der Inhalt zentriert bleibt, obwohl er umgebrochen wurde.

Min./Max. für automatische Anpassung wiederholen

Im <form> wird für jeden Abschnitt ein adaptives Rasterlayout verwendet. Das Layout wechselt je nach verfügbarem Platz von einer zu zwei Spalten.

form {
  display: grid;
  gap: var(--space-xl) var(--space-xxl);
  grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
  align-items: flex-start;
  max-width: 89vw;
}

Dieses Raster hat einen anderen Wert für row-gap (--space-xl) als für column-gap (--space-xxl), um dem responsiven Layout eine individuelle Note zu verleihen. Wenn die Spalten gestapelt werden, soll ein großer Abstand vorhanden sein, aber nicht so groß wie auf einem Breitbildschirm.

Für die Property grid-template-columns werden drei CSS-Funktionen verwendet: repeat(), minmax() und min(). Una Kravets hat dazu einen ausgezeichneten Blogbeitrag zum Layout verfasst und nennt es RAM.

Im Vergleich zu Una gibt es drei besondere Ergänzungen in unserem Layout:

  • Wir übergeben eine zusätzliche min()-Funktion.
  • Wir geben align-items: flex-start an.
  • Es gibt einen max-width: 89vw-Stil.

Die zusätzliche min()-Funktion wird von Evan Minto in seinem Blogbeitrag Intrinsically Responsive CSS Grid with minmax() and min() ausführlich beschrieben. Ich empfehle, ihn zu lesen. Die flex-start-Ausrichtungskorrektur dient dazu, den standardmäßigen Dehnungseffekt zu entfernen, sodass die untergeordneten Elemente dieses Layouts nicht die gleiche Höhe haben müssen, sondern ihre natürliche, intrinsische Höhe haben können. In diesem YouTube-Video wird die neue Ausrichtung kurz erklärt.

max-width: 89vw ist es wert, in diesem Beitrag genauer betrachtet zu werden. Hier sehen Sie das Layout mit und ohne angewendeten Stil:

Was steht an? Wenn max-width angegeben ist, wird Kontext, eine explizite Größe oder eine definitive Größe für den auto-fit-Layoutalgorithmus bereitgestellt, damit er weiß, wie viele Wiederholungen in den verfügbaren Platz passen. Es scheint zwar offensichtlich, dass der Leerraum „volle Breite“ hat, aber gemäß der CSS-Grid-Spezifikation muss eine bestimmte Größe oder maximale Größe angegeben werden. Ich habe eine maximale Größe angegeben.

Warum also 89vw? Weil es für mein Layout funktioniert hat. Ich und einige andere Chrome-Mitarbeiter untersuchen, warum ein angemessenerer Wert wie 100vw nicht ausreicht und ob es sich tatsächlich um einen Fehler handelt.

Abstand

Die Harmonie dieses Layouts beruht hauptsächlich auf einer begrenzten Palette von Abständen, genauer gesagt sieben.

:root {
  --space-xxs: .25rem;
  --space-xs:  .5rem;
  --space-sm:  1rem;
  --space-md:  1.5rem;
  --space-lg:  2rem;
  --space-xl:  3rem;
  --space-xxl: 6rem;
}

Diese Abläufe lassen sich sehr gut mit dem Raster, CSS @nest und Syntax der Stufe 5 von @media kombinieren. Hier ist ein Beispiel für den vollständigen <main>-Layoutsatz von Stilen.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
  padding: var(--space-sm);

  @media (width >= 540px) {
    & {
      padding: var(--space-lg);
    }
  }

  @media (width >= 800px) {
    & {
      padding: var(--space-xl);
    }
  }
}

Ein Raster mit zentriertem Inhalt, das standardmäßig mäßig gepolstert ist (wie auf Mobilgeräten). Wenn jedoch mehr Platz im Viewport verfügbar ist, wird es durch Erhöhen des Innenabstands verteilt. 2021 CSS sieht ziemlich gut aus.

Erinnern Sie sich an das frühere Layout „nur für Lücke“? Hier ist eine vollständigere Version der Darstellung in dieser Komponente:

header {
  display: grid;
  gap: var(--space-xxs);
}

section {
  display: grid;
  gap: var(--space-md);
}

Farbe

Durch den kontrollierten Einsatz von Farbe wirkt dieses Design ausdrucksstark und gleichzeitig minimalistisch. So gehe ich vor:

:root {
  --surface1: lch(10 0 0);
  --surface2: lch(15 0 0);
  --surface3: lch(20 0 0);
  --surface4: lch(25 0 0);

  --text1: lch(95 0 0);
  --text2: lch(75 0 0);
}

Ich benenne meine Oberflächen- und Textfarben mit Zahlen anstelle von Namen wie surface-dark und surface-darker, da ich sie in einer Media-Anfrage umkehren werde und „hell“ und „dunkel“ keine Bedeutung haben.

Ich tausche sie in einer Media-Query für die Einstellung so:

:root {
  ...

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --surface2: lch(100 0 0);
      --surface3: lch(98 0 0);
      --surface4: lch(85 0 0);

      --text1: lch(20 0 0);
      --text2: lch(40 0 0);
    }
  }
}

Bevor wir uns die Details der Farbsyntax ansehen, ist es wichtig, sich einen schnellen Überblick über das Gesamtbild und die Strategie zu verschaffen. Aber da ich etwas zu schnell war, möchte ich noch einmal einen Schritt zurückgehen.

LCH?

Ohne zu sehr in die Farbtheorie einzutauchen: LCH ist eine menschenorientierte Syntax, die darauf ausgerichtet ist, wie wir Farben wahrnehmen, und nicht darauf, wie wir Farben mathematisch messen (z. B. mit 255). Das ist ein deutlicher Vorteil, da Menschen sie leichter schreiben können und andere Menschen diese Anpassungen nachvollziehen können.

Screenshot der Webseite pod.link/csspodcast mit der Folge „Color 2: Perception“
Im CSS-Podcast erfährst du mehr über die wahrgenommene Farbe und andere Themen.

Für die heutige Vorführung konzentrieren wir uns auf die Syntax und die Werte, die ich umkehre, um Hell und Dunkel zu erzeugen. Sehen wir uns eine Oberfläche und eine Textfarbe an:

:root {
  --surface1: lch(10 0 0);
  --text1:    lch(95 0 0);

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --text1:    lch(40 0 0);
    }
  }
}

--surface1: lch(10 0 0) entspricht 10% Helligkeit, 0 Chroma und 0 Farbton: ein sehr dunkles, farbloses Grau. In der Medienabfrage für den hellen Modus wird die Helligkeit dann mit --surface1: lch(90 0 0); zu 90% umgekehrt. Das ist der Kern der Strategie. Ändern Sie zuerst nur die Helligkeit zwischen den beiden Designs und behalten Sie die Kontrastverhältnisse bei, die im Design vorgesehen sind oder die für die Barrierefreiheit erforderlich sind.

Der Vorteil bei lch() ist, dass die Helligkeit auf den Menschen ausgerichtet ist. Wir können uns also sicher sein, dass eine Änderung von % auch tatsächlich als % wahrgenommen wird. hsl() ist beispielsweise nicht so zuverlässig.

Wenn du mehr über Farbräume und lch() erfahren möchtest, findest du hier weitere Informationen. Es geht los!

CSS kann derzeit überhaupt nicht auf diese Farben zugreifen. Wir haben keinen Zugriff auf ein Drittel der Farben auf den meisten modernen Monitoren. Und das sind nicht irgendwelche Farben, sondern die kräftigsten Farben, die das Display darstellen kann. Unsere Websites sehen blass aus, weil sich die Monitore schneller weiterentwickelt haben als die CSS-Spezifikationen und Browserimplementierungen.

Lea Verou

Adaptive Formularsteuerelemente mit Farbschema

Viele Browser, derzeit Safari und Chromium, bieten Steuerelemente für das dunkle Design. Sie müssen jedoch in CSS oder HTML angeben, dass Ihr Design diese Steuerelemente verwendet.

Das Bild oben zeigt die Wirkung der Eigenschaft aus dem Bereich „Styles“ der DevTools. In der Demo wird das HTML-Tag verwendet, das meiner Meinung nach im Allgemeinen besser geeignet ist:

<meta name="color-scheme" content="dark light">

color-schemeIn diesem Artikel von Thomas Steiner finden Sie weitere Informationen. Es gibt viel mehr als nur dunkle Checkboxen.

Preisvergleichsportal accent-color

Es gab kürzlich Aktivitäten im Zusammenhang mit accent-color für Formularelemente. Dabei handelt es sich um einen einzelnen CSS-Stil, mit dem die im Eingabeelement des Browsers verwendete Tönungsfarbe geändert werden kann. Weitere Informationen auf GitHub Ich habe sie in die Stile für diese Komponente aufgenommen. Wenn Browser das unterstützen, passen meine Kästchen besser zum Design mit den pinken und lila Akzentfarben.

input[type="checkbox"] {
  accent-color: var(--brand);
}

Screenshot von Chromium unter Linux mit rosa Kästchen

Color Pop-Fotos mit festen Farbverläufen und Fokus-in-Funktion

Farben kommen am besten zur Geltung, wenn sie sparsam eingesetzt werden. Eine Möglichkeit, dies zu erreichen, sind farbenfrohe UI-Interaktionen.

Das Video oben enthält viele Ebenen von UI-Feedback und Interaktion, die der Interaktion Persönlichkeit verleihen:

  • Kontext hervorheben
  • UI-Feedback dazu geben, wie „voll“ der Wert im Bereich ist.
  • Feedback zur Benutzeroberfläche geben, dass ein Feld Eingaben akzeptiert.

Um Feedback zu geben, wenn mit einem Element interagiert wird, wird in CSS die Pseudoklasse :focus-within verwendet, um das Aussehen verschiedener Elemente zu ändern. Sehen wir uns die .fieldset-item genauer an:

.fieldset-item {
  ...

  &:focus-within {
    background: var(--surface2);

    & svg {
      fill: white;
    }

    & picture {
      clip-path: circle(50%);
      background: var(--brand-bg-gradient) fixed;
    }
  }
}

Wenn eines der untergeordneten Elemente dieses Elements den Fokus hat:

  1. Dem .fieldset-item-Hintergrund wird eine Oberflächenfarbe mit höherem Kontrast zugewiesen.
  2. Das verschachtelte svg ist für einen höheren Kontrast weiß gefüllt.
  3. Das verschachtelte <picture> clip-path wird zu einem Vollkreis erweitert und der Hintergrund wird mit dem hellen festen Farbverlauf gefüllt.

Benutzerdefinierter Zeitraum

Anhand des folgenden HTML-Eingabeelements zeige ich Ihnen, wie ich sein Erscheinungsbild angepasst habe:

<input type="range">

Dieses Element besteht aus drei Teilen, die wir anpassen müssen:

  1. Bereichselement / Container
  2. Track
  3. Daumen

Stile für Bereichselemente

input[type="range"] {
  /* style setting variables */
  --track-height: .5ex;
  --track-fill: 0%;
  --thumb-size: 3ex;
  --thumb-offset: -1.25ex;
  --thumb-highlight-size: 0px;

  appearance: none;         /* clear styles, make way for mine */
  display: block;
  inline-size: 100%;        /* fill container */
  margin: 1ex 0;            /* ensure thumb isn't colliding with sibling content */
  background: transparent;  /* bg is in the track */
  outline-offset: 5px;      /* focus styles have space */
}

Die ersten Zeilen des CSS sind die benutzerdefinierten Teile der Formatierungen. Ich hoffe, dass die klare Kennzeichnung hilft. Die restlichen Stile sind größtenteils Reset-Stile, um eine einheitliche Grundlage für die schwierigen Teile der Komponente zu schaffen.

Track-Stile

input[type="range"]::-webkit-slider-runnable-track {
  appearance: none; /* clear styles, make way for mine */
  block-size: var(--track-height);
  border-radius: 5ex;
  background:
    /* hard stop gradient:
        - half transparent (where colorful fill we be)
        - half dark track fill
        - 1st background image is on top
    */
    linear-gradient(
      to right,
      transparent var(--track-fill),
      var(--surface1) 0%
    ),
    /* colorful fill effect, behind track surface fill */
    var(--brand-bg-gradient) fixed;
}

Der Trick dabei ist, die leuchtende Füllfarbe „aufzudecken“. Dazu wird der Gradient mit dem harten Stopp oben verwendet. Der Farbverlauf ist bis zum Füllprozentsatz transparent. Danach wird die Farbe der Oberfläche des nicht gefüllten Tracks verwendet. Hinter dieser nicht gefüllten Fläche befindet sich eine Farbe in voller Breite, die durch Transparenz sichtbar wird.

Track-Füllstil

Für mein Design ist JavaScript erforderlich, damit der Füllstil beibehalten wird. Es gibt nur CSS-Strategien, aber dafür muss das Thumb-Element die gleiche Höhe wie der Track haben. Ich konnte keine Lösung finden, die diese Einschränkungen erfüllt.

/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')

/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
  const max = slider.getAttribute('max') || 10;
  const percent = slider.value / max * 100;

  return `${parseInt(percent)}%`;
};

/* on page load, set the fill amount */
sliders.forEach(slider => {
  slider.style.setProperty('--track-fill', rangeToPercent(slider));

  /* when a slider changes, update the fill prop */
  slider.addEventListener('input', e => {
    e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
  })
})

Ich finde, das ist eine schöne visuelle Verbesserung. Der Schieberegler funktioniert auch ohne JavaScript. Die --track-fill-Eigenschaft ist nicht erforderlich. Wenn sie nicht vorhanden ist, wird einfach kein Füllstil verwendet. Wenn JavaScript verfügbar ist, füllen Sie die benutzerdefinierte Eigenschaft aus und berücksichtigen Sie dabei alle Nutzeränderungen. Synchronisieren Sie die benutzerdefinierte Eigenschaft mit dem Wert.

In diesem Beitrag auf CSS-Tricks von Ana Tudor wird eine reine CSS-Lösung für die Füllung von Tracks vorgestellt. Ich fand auch dieses range-Element sehr inspirierend.

Thumb-Stile

input[type="range"]::-webkit-slider-thumb {
  appearance: none; /* clear styles, make way for mine */
  cursor: ew-resize; /* cursor style to support drag direction */
  border: 3px solid var(--surface3);
  block-size: var(--thumb-size);
  inline-size: var(--thumb-size);
  margin-top: var(--thumb-offset);
  border-radius: 50%;
  background: var(--brand-bg-gradient) fixed;
}

Die meisten dieser Stile sind dazu da, einen schönen Kreis zu bilden. Auch hier sehen Sie den fixierten Hintergrund-Farbverlauf, der die dynamischen Farben der Thumbnails, Tracks und zugehörigen SVG-Elemente vereinheitlicht. Ich habe die Stile für die Interaktion getrennt, um die box-shadow-Technik zu isolieren, die für die Hervorhebung beim Hovern verwendet wird:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

::-webkit-slider-thumb {
  

  /* shadow spread is initally 0 */
  box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);

  /* if motion is OK, transition the box-shadow change */
  @media (--motionOK) {
    & {
      transition: box-shadow .1s ease;
    }
  }

  /* on hover/active state of parent, increase size prop */
  @nest input[type="range"]:is(:hover,:active) & {
    --thumb-highlight-size: 10px;
  }
}

Ziel war es, Nutzerfeedback auf einfache Weise zu verwalten und visuell hervorzuheben. Durch die Verwendung eines Schlagschattens kann ich vermeiden, dass der Effekt das Layout auslöst. Dazu erstelle ich einen Schatten, der nicht weichgezeichnet ist und der runden Form des Thumb-Elements entspricht. Dann ändere ich die Größe des Bildes beim Hovern und sorge für einen Übergang.

Wenn das Hervorheben von Checkboxen doch nur so einfach wäre…

Browserübergreifende Selektoren

Ich habe festgestellt, dass ich die Selektoren -webkit- und -moz- benötige, um die browserübergreifende Konsistenz zu erreichen:

input[type="range"] {
  &::-webkit-slider-runnable-track {}
  &::-moz-range-track {}
  &::-webkit-slider-thumb {}
  &::-moz-range-thumb {}
}

Benutzerdefiniertes Kästchen

Anhand des folgenden HTML-Eingabeelements zeige ich Ihnen, wie ich sein Erscheinungsbild angepasst habe:

<input type="checkbox">

Dieses Element besteht aus drei Teilen, die wir anpassen müssen:

  1. Kästchen
  2. Zugeordnete Labels
  3. Highlight-Effekt

Kästchen-Element

input[type="checkbox"] {
  inline-size: var(--space-sm);   /* increase width */
  block-size: var(--space-sm);    /* increase height */
  outline-offset: 5px;            /* focus style enhancement */
  accent-color: var(--brand);     /* tint the input */
  position: relative;             /* prepare for an absolute pseudo element */
  transform-style: preserve-3d;   /* create a 3d z-space stacking context */
  margin: 0;
  cursor: pointer;
}

Mit den Formatierungen transform-style und position wird das Pseudoelement vorbereitet, das wir später zum Formatieren der Hervorhebung einführen. Ansonsten sind es meistens kleinere stilistische Änderungen von mir. Der Cursor soll als Zeiger dargestellt werden, ich möchte Umriss-Offsets verwenden, die Standard-Kästchen sind zu klein und wenn accent-color unterstützt wird, sollen diese Kästchen in das Farbdesign der Marke aufgenommen werden.

Kästchen-Labels

Es ist aus zwei Gründen wichtig, Labels für Checkboxen anzugeben. Erstens, um darzustellen, wofür der Kästchenwert verwendet wird, um die Frage „An oder aus für was?“ zu beantworten. Zweitens ist es für die Nutzerfreundlichkeit wichtig, da Webnutzer es gewohnt sind, mit Checkboxen über die zugehörigen Labels zu interagieren.

Eingabe
<input
  type="checkbox"
  id="text-notifications"
  name="text-notifications"
>
Label
<label for="text-notifications">
  <h3>Text Messages</h3>
  <small>Get notified about all text messages sent to your device</small>
</label>

Fügen Sie dem Label ein for-Attribut hinzu, das anhand der ID auf ein Kontrollkästchen verweist: <label for="text-notifications">. Verdoppeln Sie sowohl den Namen als auch die ID des Kontrollkästchens, damit es mit verschiedenen Tools und Technologien wie einer Maus oder einem Screenreader gefunden werden kann: <input type="checkbox" id="text-notifications" name="text-notifications">. :hover, :active und mehr sind kostenlos in der Verbindung enthalten. So können Nutzer auf mehr Arten mit Ihrem Formular interagieren.

Hervorhebung von Kästchen

Ich möchte, dass meine Benutzeroberflächen einheitlich aussehen. Das Slider-Element hat eine schöne Miniaturansicht, die ich auch für das Kästchen verwenden möchte. Für das Thumbnail konnte box-shadow verwendet werden und mit dem Attribut spread konnte ein Schatten vergrößert und verkleinert werden. Dieser Effekt funktioniert hier jedoch nicht, da unsere Kästchen quadratisch sind und sein sollten.

Ich konnte denselben visuellen Effekt mit einem Pseudoelement und einer unglücklichen Menge an kniffligem CSS erzielen:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

input[type="checkbox"]::before {
  --thumb-scale: .01;                        /* initial scale of highlight */
  --thumb-highlight-size: var(--space-xl);

  content: "";
  inline-size: var(--thumb-highlight-size);
  block-size: var(--thumb-highlight-size);
  clip-path: circle(50%);                     /* circle shape */
  position: absolute;                         /* this is why position relative on parent */
  top: 50%;                                   /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
  left: 50%;
  background: var(--thumb-highlight-color);
  transform-origin: center center;            /* goal is a centered scaling circle */
  transform:                                  /* order here matters!! */
    translateX(-50%)                          /* counter balances left: 50% */
    translateY(-50%)                          /* counter balances top: 50% */
    translateZ(-1px)                          /* PUTS IT BEHIND THE CHECKBOX */
    scale(var(--thumb-scale))                 /* value we toggle for animation */
  ;
  will-change: transform;

  @media (--motionOK) {                       /* transition only if motion is OK */
    & {
      transition: transform .2s ease;
    }
  }
}

/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
  --thumb-scale: 1;
}

Ein Pseudo-Element in Form eines Kreises zu erstellen, ist einfach, aber es hinter dem Element zu platzieren, an das es angehängt ist, war schwieriger. Hier sehen Sie, wie es vor und nach der Korrektur aussieht:

Es ist definitiv eine Mikrointeraktion, aber es ist mir wichtig, die visuelle Konsistenz beizubehalten. Die Skalierungstechnik für Animationen ist dieselbe wie an anderen Stellen. Wir legen eine benutzerdefinierte Property auf einen neuen Wert fest und lassen sie von CSS basierend auf den Einstellungen für die Bewegung übergehen. Die wichtigste Funktion ist translateZ(-1px). Das übergeordnete Element hat einen 3D-Raum erstellt und das untergeordnete Pseudo-Element hat ihn genutzt, indem es sich etwas weiter hinten im Z-Raum platziert hat.

Bedienungshilfen

Das YouTube-Video zeigt die Maus-, Tastatur- und Screenreader-Interaktionen für diese Einstellungs-Komponente. Ich werde hier einige Details nennen.

Auswahl von HTML-Elementen

<form>
<header>
<fieldset>
<picture>
<label>
<input>

Jeder dieser Holds enthält Hinweise und Tipps für das Browsing-Tool des Nutzers. Einige Elemente enthalten Hinweise zur Interaktion, andere verbinden Interaktivität und wieder andere helfen dabei, den Barrierefreiheitsbaum zu gestalten, in dem ein Screenreader navigiert.

HTML-Attribute

Wir können Elemente ausblenden, die nicht von Screenreadern benötigt werden, in diesem Fall das Symbol neben dem Schieberegler:

<picture aria-hidden="true">

Im obigen Video wird der Screenreader-Ablauf unter Mac OS gezeigt. Beachten Sie, wie der Eingabefokus direkt von einem Schieberegler zum nächsten wechselt. Das liegt daran, dass wir das Symbol ausgeblendet haben, das möglicherweise ein Zwischenstopp auf dem Weg zum nächsten Slider war. Ohne dieses Attribut müsste ein Nutzer anhalten, zuhören und das Bild überspringen, das er möglicherweise nicht sehen kann.

Das SVG besteht aus einer Reihe von mathematischen Formeln. Fügen wir ein <title>-Element für einen kostenlosen Titel beim Mauszeiger und einen für Menschen lesbaren Kommentar dazu ein, was durch die mathematischen Formeln erstellt wird:

<svg viewBox="0 0 24 24">
  <title>A note icon</title>
  <path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>

Ansonsten haben wir genügend deutlich gekennzeichnetes HTML verwendet, sodass die Formular-Tests mit Maus, Tastatur, Gamecontrollern und Screenreadern sehr gut funktionieren.

JavaScript

Ich habe bereits beschrieben, wie die Farbe für den Track-Fill aus JavaScript verwaltet wurde. Sehen wir uns nun das zugehörige JavaScript für <form> an:

const form = document.querySelector('form');

form.addEventListener('input', event => {
  const formData = Object.fromEntries(new FormData(form));
  console.table(formData);
})

Jedes Mal, wenn das Formular verwendet und geändert wird, wird es in der Konsole als Objekt in einer Tabelle protokolliert, damit es vor dem Senden an einen Server einfach überprüft werden kann.

Ein Screenshot der Ergebnisse von „console.table()“, in dem die Formulardaten in einer Tabelle dargestellt werden

Fazit

Jetzt wissen Sie, wie ich es gemacht habe. Wie würden Sie es machen? Das ist eine interessante Komponentenarchitektur. Wer erstellt die erste Version mit Slots in seinem bevorzugten Framework? 🙂

Wir möchten unsere Ansätze diversifizieren und alle Möglichkeiten kennenlernen, die das Web bietet. Erstelle eine Demo, schick mir einen Tweet mit Links und ich füge sie unten im Abschnitt Community-Remixe hinzu.

Community-Remixe

  • @tomayac für den Stil des Mauszeigerbereichs für die Checkbox-Labels. Diese Version hat keinen Hover-Abstand zwischen den Elementen: Demo und Quelle.