Einstellungen-Komponente erstellen

Eine grundlegende Übersicht über das Erstellen einer Einstellungskomponente mit Schiebereglern und Kästchen.

In diesem Beitrag möchte ich meine Überlegungen zum Erstellen einer responsiven Einstellungskomponente für das Web teilen, die mehrere Geräteeingaben unterstützt und browserübergreifend funktioniert. Demo ausprobieren

Demo

Wenn Sie ein Video bevorzugen oder eine UI/UX-Vorschau des Projekts 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. Benutzerdefiniertes Kästchen
  5. Barrierefreiheit möglich machen
  6. JavaScript

Layouts

Dies ist die erste GUI Challenge-Demo, die vollständig auf CSS Grid basiert. Hier sind die einzelnen Raster mit den Chrome-Entwicklertools für Raster hervorgehoben:

Bunte Umrisse und Abstandsüberlagerungen, die alle Felder des Einstellungslayouts zeigen

Nur für Lücke

Das gängigste Layout:

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

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

Fünf Layouts verwenden diese Strategie. Hier sind alle aufgeführt:

Vertikale Rasterlayouts mit Umrissen und ausgefüllten Lücken

Das Element fieldset, das jede Eingabegruppe (.fieldset-item) enthält, verwendet gap: 1px, um die Haarlinien zwischen den Elementen zu erstellen. Keine komplizierte Lösung für die Grenze!

Lücke gefüllt
.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 Makro-Layout, das logische Layoutsystem zwischen <main> und <form>.

Zentrieren von umbrochenem Inhalt

Sowohl Flexbox als auch Grid bieten die Möglichkeit, align-items oder align-content. Wenn Sie mit umbrechenden Elementen arbeiten, werden bei content-Layoutausrichtungen die Abstände zwischen den untergeordneten Elementen als Gruppe verteilt.

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

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

Im Video oben sehen Sie, wie der „Inhalt“ zentriert bleibt, obwohl ein Zeilenumbruch stattgefunden hat.

Minmax für automatische Anpassung wiederholen

Die <form> verwendet für jeden Abschnitt ein adaptives Rasterlayout. Dieses 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 column-gap (--space-xxl), um dem responsiven Layout eine individuelle Note zu verleihen. Wenn die Spalten gestapelt werden, soll der Abstand groß sein, aber nicht so groß wie auf einem breiten Bildschirm.

Die Property grid-template-columns verwendet drei CSS-Funktionen: repeat(), minmax() und min(). Una Kravets hat einen großartigen Blogpost zum Thema Layout verfasst, in dem sie es RAM nennt.

Unser Layout enthält drei besondere Ergänzungen im Vergleich zu dem von Una:

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

Die zusätzliche Funktion min() wird von Evan Minto in seinem Blog im Beitrag Intrinsically Responsive CSS Grid with minmax() and min() gut beschrieben. Ich empfehle, diesen Beitrag zu lesen. Die Ausrichtungskorrektur flex-start entfernt den standardmäßigen Streckungseffekt, sodass die untergeordneten Elemente dieses Layouts nicht dieselbe Höhe haben müssen, sondern natürliche, intrinsische Höhen haben können. In diesem YouTube-Video wird diese neue Ausrichtungsoption kurz erläutert.

max-width: 89vw ist es wert, in diesem Beitrag kurz erläutert zu werden. Hier sehen Sie das Layout mit und ohne den Stil:

Was steht an? Wenn max-width angegeben ist, wird dem auto-fit-Layoutalgorithmus Kontext, eine explizite Größe oder eine definitive Größe bereitgestellt, damit er weiß, wie viele Wiederholungen in den Bereich passen. Es scheint zwar offensichtlich, dass der Bereich gemäß der CSS-Grid-Spezifikation die „volle Breite“ hat, es muss jedoch 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 ein paar andere Chrome-Mitarbeiter untersuchen, warum ein vernünftigerer Wert wie 100vw nicht ausreicht und ob es sich tatsächlich um einen Fehler handelt.

Abstand

Die Harmonie dieses Layouts beruht größtenteils auf einer begrenzten Auswahl an Abständen, genauer gesagt 7.

: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 Grid, CSS @nest und der @media-Syntax der Stufe 5 kombinieren. Hier ist ein Beispiel für die vollständigen <main>-Layoutstile.

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, der standardmäßig mäßig gepolstert ist (wie auf Mobilgeräten). Wenn jedoch mehr Platz im Darstellungsbereich verfügbar ist, wird er durch Erhöhen des Abstands verteilt. Das CSS von 2021 sieht ziemlich gut aus!

Erinnern Sie sich an das vorherige Layout „nur für Lücken“? Hier ist eine vollständigere Version, wie sie in dieser Komponente aussehen:

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

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

Farbe

Durch den kontrollierten Einsatz von Farben wirkt dieses Design ausdrucksstark und gleichzeitig minimalistisch. Ich mache das so:

: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 und nicht mit Namen wie surface-dark und surface-darker, da ich sie in einer Medienabfrage umkehre und hell und dunkel dann nicht mehr aussagekräftig sind.

Ich kehre sie in einer Medienabfrage für Einstellungen so um:

: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);
    }
  }
}

Es ist wichtig, sich einen Überblick über das Gesamtbild und die Strategie zu verschaffen, bevor wir uns mit den Details der Farbsyntax befassen. Aber ich bin etwas zu schnell. Gehen wir noch einmal einen Schritt zurück.

LCH?

Ohne zu tief in die Farbtheorie einzusteigen, ist LCH eine menschenorientierte Syntax, die darauf ausgerichtet ist, wie wir Farben wahrnehmen, und nicht darauf, wie wir Farben mit Mathematik messen (z. B. 255). Das ist ein großer 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“
Weitere Informationen zu wahrnehmungsbezogenen Farben (und mehr) im CSS Podcast

In dieser Demo konzentrieren wir uns auf die Syntax und die Werte, die ich für den hellen und dunklen Modus ändere. Sehen wir uns eine Oberflächen- 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 einer Helligkeit von 10%, einer Farbsättigung von 0 und einem Farbton von 0: ein sehr dunkles, farbloses Grau. In der Medienabfrage für den hellen Modus wird die Helligkeit dann mit --surface1: lch(90 0 0); auf 90% umgestellt. Das ist im Wesentlichen die Strategie. Beginnen Sie damit, nur die Helligkeit zwischen den beiden Designs zu ändern. Behalten Sie dabei die Kontrastverhältnisse bei, die das Design erfordert oder die für die Barrierefreiheit im Internet erforderlich sind.

Der Vorteil von lch() ist, dass die Helligkeit auf den Menschen ausgerichtet ist. Wir können uns also darauf verlassen, dass eine Änderung um % wahrnehmbar und konsistent ist%. hsl() ist beispielsweise nicht so zuverlässig.

Wenn Sie mehr über Farbräume und lch() erfahren möchten, finden Sie hier weitere Informationen. Es kommt!

CSS kann derzeit überhaupt nicht auf diese Farben zugreifen. Ich wiederhole: Wir haben keinen Zugriff auf ein Drittel der Farben auf den meisten modernen Monitoren. Und das sind nicht irgendwelche Farben, sondern die lebendigsten Farben, die das Display darstellen kann. Unsere Websites sind verwaschen, weil sich die Monitorhardware schneller entwickelt hat 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 verwendet.

Oben wird der Effekt der Property im Bereich „Stile“ der Entwicklertools veranschaulicht. In der Demo wird das HTML-Tag verwendet, was meiner Meinung nach im Allgemeinen eine bessere Position ist:

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

Weitere Informationen finden Sie in diesem color-scheme-Artikel von Thomas Steiner. Es gibt noch viel mehr zu gewinnen als dunkle Kästcheneingaben!

CSS accent-color

In letzter Zeit gab es Aktivitäten rund um accent-color für Formularelemente. Dabei handelt es sich um einen einzelnen CSS-Stil, mit dem die im Eingabeelement des Browsers verwendete Farbtonfarbe geändert werden kann. Weitere Informationen finden Sie hier auf GitHub. Ich habe sie in meine Stile für diese Komponente aufgenommen. Da Browser dies unterstützen, passen meine Kästchen mit den pinken und lila Farbakzenten besser zum Design.

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

Screenshot von Chromium unter Linux mit pinkfarbenen Kästchen

Color Pop-Effekte mit festen Farbverläufen und „focus-within“

Farbe kommt am besten zur Geltung, wenn sie sparsam eingesetzt wird. Eine Möglichkeit, dies zu erreichen, sind farbenfrohe UI-Interaktionen.

Im Video oben gibt es viele Ebenen von UI-Feedback und -Interaktion, die der Interaktion Persönlichkeit verleihen:

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

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

.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 „focus-within“ hat:

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

Zeitraum auswählen

Anhand des folgenden HTML-Eingabeelements zeige ich Ihnen, wie ich das 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 paar Zeilen des CSS sind die benutzerdefinierten Teile der Stile. Ich hoffe, dass die klare Kennzeichnung hilfreich ist. Die restlichen Stile sind hauptsächlich Reset-Stile, um eine einheitliche Grundlage für die Erstellung der 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 Hard-Stop-Farbverlauf oben verwendet. Der Farbverlauf ist bis zum Füllprozentsatz transparent und verwendet danach die Farbe der ungefüllten Trackoberfläche. Hinter dieser ungefüllten Oberfläche befindet sich eine Farbe, die die gesamte Breite einnimmt und durch die Transparenz sichtbar wird.

Füllfarbe des Schiebereglers

Mein Design erfordert JavaScript, um den Füllstil beizubehalten. Es gibt reine CSS-Strategien, aber sie erfordern, dass das Daumenelement dieselbe Höhe wie die Spur hat, und ich konnte innerhalb dieser Grenzen keine Harmonie finden.

/* 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 ein schönes visuelles Upgrade. Der Schieberegler funktioniert auch ohne JavaScript. Das Attribut --track-fill ist nicht erforderlich. Wenn es nicht vorhanden ist, wird einfach kein Füllstil verwendet. Wenn JavaScript verfügbar ist, füllen Sie die benutzerdefinierte Eigenschaft aus und beobachten Sie gleichzeitig 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 Track-Füllung vorgestellt. Ich fand auch dieses range-Element sehr inspirierend.

Stile für Schieberegler

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 dienen dazu, einen schönen Kreis zu erstellen. Auch hier sehen Sie den festen Hintergrundverlauf, der die dynamischen Farben der Schieberegler, Schienen und zugehörigen SVG-Elemente vereinheitlicht. Ich habe die Stile für die Interaktion getrennt, um die box-shadow-Technik, die für die Hover-Hervorhebung verwendet wird, zu isolieren:

@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, ein einfach zu verwaltendes und animiertes visuelles Highlight für Nutzerfeedback zu schaffen. Durch die Verwendung eines Box-Shadows kann ich vermeiden, dass der Effekt ein 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 Schattens beim Hovern und füge einen Übergang hinzu.

Wenn es doch nur so einfach wäre, den Hervorhebungseffekt auf Kästchen anzuwenden…

Browserübergreifende Selektoren

Ich habe festgestellt, dass ich diese -webkit-- und -moz--Selektoren benötige, um eine 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 das Erscheinungsbild angepasst habe:

<input type="checkbox">

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

  1. Kästchen
  2. Verknüpfte Labels
  3. Highlight-Effekt

Kästchenelement

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;
}

Die Stile transform-style und position bereiten das Pseudoelement vor, das wir später einführen, um die Hervorhebung zu gestalten. Ansonsten sind es meist nur kleinere, subjektive Stilfragen von mir. Ich möchte, dass der Cursor ein Zeiger ist, ich möchte Outline-Offsets, die Standard-Kästchen sind zu klein und wenn accent-color unterstützt wird, möchte ich, dass diese Kästchen im Farbschema der Marke angezeigt werden.

Kästchen-Labels

Es ist aus zwei Gründen wichtig, Labels für Kästchen anzugeben. Der erste ist, darzustellen, wofür der Wert des Kästchens verwendet wird, um die Frage „An oder aus für was?“ zu beantworten. Zweitens sind Webnutzer es gewohnt, mit Kästchen ü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 auf ein Kästchen mit der ID <label for="text-notifications"> verweist. Verwenden Sie für das Kästchen sowohl den Namen als auch die ID, 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 weitere Funktionen sind kostenlos in der Verbindung enthalten und bieten mehr Möglichkeiten, mit Ihrem Formular zu interagieren.

Kästchen hervorheben

Ich möchte meine Benutzeroberflächen einheitlich gestalten und das Schieberegler-Element hat eine schöne Thumbnail-Hervorhebung, die ich mit dem Kästchen verwenden möchte. In der Miniaturansicht konnten box-shadow und die zugehörige Eigenschaft spread verwendet werden, um einen Schatten zu vergrößern und zu verkleinern. 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;
}

Das Erstellen eines Kreis-Pseudoelements ist einfach, aber es hinter dem Element zu platzieren, an das es angehängt ist, war schwieriger. Hier ist der Code vor und nach der Korrektur:

Das ist definitiv eine Mikrointeraktion, aber mir ist es wichtig, die visuelle Konsistenz beizubehalten. Die Technik zur Skalierung der Animation ist dieselbe, die wir auch an anderen Stellen verwendet haben. Wir legen für eine benutzerdefinierte Eigenschaft einen neuen Wert fest und lassen sie von CSS basierend auf den Bewegungseinstellungen umwandeln. Die wichtigste Funktion ist hier translateZ(-1px). Das übergeordnete Element hat einen 3D-Bereich erstellt und das untergeordnete Pseudoelement hat diesen Bereich genutzt, indem es sich etwas weiter hinten im Z-Bereich platziert hat.

Bedienungshilfen

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

HTML-Elementauswahl

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

Jede dieser Optionen enthält Hinweise und Tipps zum Browser-Tool des Nutzers. Einige Elemente bieten Interaktionshinweise, andere verbinden Interaktivität und wieder andere helfen, den Baum für Barrierefreiheit zu formen, durch den ein Screenreader navigiert.

HTML-Attribute

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

<picture aria-hidden="true">

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

Die SVG-Datei enthält eine Reihe von mathematischen Formeln. Fügen wir ein <title>-Element für einen Titel hinzu, der beim Bewegen des Mauszeigers angezeigt wird, und einen menschenlesbaren Kommentar dazu, was die Formeln bewirken:

<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 klar gekennzeichnetes HTML verwendet, sodass das Formular mit Maus, Tastatur, Videospiel-Controllern und Screenreadern sehr gut funktioniert.

JavaScript

Ich habe bereits erläutert, wie die Füllfarbe des Tracks über JavaScript verwaltet wird. Sehen wir uns jetzt 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 mit dem Formular interagiert und es geändert wird, wird es von der Console als Objekt in einer Tabelle protokolliert, damit es vor dem Senden an einen Server einfach überprüft werden kann.

Screenshot der console.table()-Ergebnisse, in denen die Formulardaten in einer Tabelle angezeigt werden

Fazit

Jetzt, da du weißt, wie ich es gemacht habe, wie würdest du es machen?! Das sorgt für eine interessante Komponentenarchitektur. Wer erstellt die erste Version mit Slots in seinem Lieblings-Framework? 🙂

Lassen Sie uns unsere Ansätze diversifizieren und alle Möglichkeiten kennenlernen, wie wir im Web entwickeln können. Erstellen Sie eine Demo, twittern Sie mir Links und ich füge sie dem Abschnitt Community-Remixe unten hinzu.

Community-Remixe

  • @tomayac für den Stil des Hover-Bereichs für die Checkbox-Labels. Diese Version hat keine Lücke zwischen den Elementen: Demo und Quelle.