Eine Ladebalkenkomponente erstellen

Ein grundlegender Überblick darüber, wie du mit dem Element <progress> eine adaptive und barrierefreie Ladeleiste erstellst.

In diesem Beitrag möchte ich darauf eingehen, wie Sie eine adaptive Farbe zugängliche Ladeleiste mit dem Element <progress>. Testen Sie Demo-Video und sehen Sie sich die Quelle.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> Hell und dunkel, unbestimmt, ansteigend und vollständig in Chrome getestet.

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

Übersicht

Die <progress> gibt den Nutzenden visuelles und akustisches Feedback zum Abschluss. Dieses visuelles Feedback ist hilfreich für Szenarien wie den Fortschritt eines Formulars, um Informationen zum Herunterladen oder Hochladen anzuzeigen oder sogar zu zeigen, Fortschrittsgrad ist unbekannt, aber Arbeit ist noch aktiv.

Bei dieser GUI Challenge wurde das vorhandene HTML-<progress>-Element verwenden, um die Barrierefreiheit zu verbessern. Die Farben und Layouts die Grenzen der Anpassung für das integrierte Element aus, die Komponente zu modernisieren und besser in Designsysteme zu integrieren.

<ph type="x-smartling-placeholder">
</ph> Helle und dunkle Tabs in jedem Browser bieten 
    Übersicht über das adaptive Symbol von oben nach unten: 
    Safari, Firefox, Chrome. <ph type="x-smartling-placeholder">
</ph> Diese Demo ist für Firefox, Safari, iOS Safari Chrome und Android Chrome in hellen und dunklen Gegebenheiten.

Markup

Ich habe mich entschieden, das <progress>-Element mit einem <label> damit Ich könnte die expliziten Beziehungsattribute zugunsten einer impliziten Beziehung. Ich habe auch ein übergeordnetes Element beschriftet, das vom Ladestatus betroffen ist. Lesetechnologien können diese Informationen an die Nutzenden zurückgeben.

<progress></progress>

Ist kein value vorhanden, beträgt der Fortschritt des Elements unbestimmt. Das Attribut max ist standardmäßig auf 1 gesetzt, der Fortschritt liegt also zwischen 0 und 1. max wird festgelegt 100 setzen, wird der Bereich auf 0 bis 100 gesetzt. Ich habe mich dafür entschieden, innerhalb der 0 zu bleiben. und 1 Grenzwerte, wodurch die Fortschrittswerte in 0,5 oder 50 % übersetzt werden.

Fortschritt bei Label-Wrapping

In einer impliziten Beziehung wird ein Fortschrittselement wie folgt von einem Label umschlossen:

<label>Loading progress<progress></progress></label>

In meiner Demo habe ich mich dafür entschieden, das Label für Screenreader . Dazu wird der Labeltext in einem <span> umgebrochen und es werden Stile angewendet zu verschieben, damit es sich außerhalb des Bildschirms befindet:

<label>
  <span class="sr-only">Loading progress</span>
  <progress></progress>
</label>

Mit folgendem CSS-Code von WebAIM:

.sr-only {
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: inset(50%);
  height: 1px;
  width: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
}

Screenshot der Entwicklertools mit dem Bildschirmelement, das nur für den Bildschirm bereit ist.

Vom Ladefortschritt betroffene Bereiche

Wenn du ein gesundes Sehvermögen hast, kann es leicht sein, eine Fortschrittsanzeige mit verwandten Elementen und Seitenbereichen, aber für sehbehinderte Nutzende so klar. Sie können dies verbessern, indem Sie die aria-busy -Attribut zum obersten Element hinzu, das sich ändert, wenn der Ladevorgang abgeschlossen ist. Zeigen Sie außerdem eine Beziehung zwischen dem Fortschritt und der Ladezone an. mit aria-describedby

<main id="loading-zone" aria-busy="true">
  …
  <progress aria-describedby="loading-zone"></progress>
</main>

In JavaScript wechseln Sie zu Beginn der Aufgabe mit der Umschaltoption aria-busy in true und false:

Hinzufügungen von Aria-Attributen

Die implizite Rolle eines <progress>-Elements ist progressbar, ich habe das explizit angegeben für Browser ohne diese implizite Rolle. Ich habe auch das Attribut indeterminate, um das Element explizit in den Status „Unbekannt“ zu versetzen. klarer ist, als das Element zu beobachten, kein value festgelegt ist.

<label>
  Loading 
  <progress 
    indeterminate 
    role="progressbar" 
    aria-describedby="loading-zone"
    tabindex="-1"
  >unknown</progress>
</label>

Verwenden Sie tabindex="-1" damit das Fortschrittselement von JavaScript aus fokussierbar ist. Das ist wichtig für Screenreader-Technologie zu verwenden, da der Fortschritt informiert den Nutzer darüber, wie weit der aktualisierte Fortschritt bereits erreicht ist.

Stile

Das Progress-Element ist etwas komplizierter. Integriertes HTML weisen besondere versteckte Teile auf, die schwer auszuwählen sind und nur eine begrenzte Anzahl von Properties zur Verfügung stellen.

Layout

Die Layout-Stile sollen eine gewisse Flexibilität bei der Entwicklung ermöglichen. der Größe und der Label-Position des Elements. Es wird ein spezieller Abschlussstatus hinzugefügt, der ein nützlicher, aber nicht unbedingt erforderlicher zusätzlicher visueller Hinweis.

<progress>-Layout

Die Breite des Fortschrittselements bleibt unverändert, sodass es verkleinern und vergrößern kann. mit dem benötigten Raum im Design. Die integrierten Stile sind appearance und border werden auf none festgelegt. So kann das Element browserübergreifend normalisiert, da jeder Browser seine eigenen Stile -Elements.

progress {
  --_track-size: min(10px, 1ex);
  --_radius: 1e3px;

  /*  reset  */
  appearance: none;
  border: none;

  position: relative;
  height: var(--_track-size);
  border-radius: var(--_radius);
  overflow: hidden;
}

Der Wert von 1e3px für _radius verwendet eine wissenschaftliche Zahl , um eine bestimmte große Zahl, damit border-radius immer gerundet wird. Entspricht 1000px Ich verwende sie gerne, weil ich einen Wert verwenden möchte, der groß genug ist, Ich kann es festlegen und entkoppeln (und es ist kürzer als 1000px). Es ist auch bei Bedarf ganz einfach vergrößern: Ändern Sie einfach die 3 in eine 4, dann ist 1e4px gleichbedeutend mit 10000px.

overflow: hidden“ wurde in einem strittigen Stil verwendet. Das machte einige So müssen Sie beispielsweise border-radius-Werte nicht an den Füllelemente verfolgen und verfolgen. aber auch den Fortschritt nicht nachzuahmen, außerhalb des Elements leben. Eine weitere Iteration dieses benutzerdefinierten Fortschritts kann ohne overflow: hidden erstellt werden, wodurch einige Animationen oder einen besseren Abschlussstatus zu erzielen.

Vorgang abgeschlossen

CSS-Selektoren erledigen hier die schwierige Arbeit, indem sie den Maximalwert mit dem Wert vergleichen. Wenn sie übereinstimmen, ist der Fortschritt abgeschlossen. Nach Abschluss wird ein Pseudoelement generiert und an das Ende des progress -Elements angehängt, das einen schönen zusätzlichen visuellen Hinweis auf den Abschluss bietet.

progress:not([max])[value="1"]::before,
progress[max="100"][value="100"]::before {
  content: "";
  
  position: absolute;
  inset-block: 0;
  inset-inline: auto 0;
  display: flex;
  align-items: center;
  padding-inline-end: max(calc(var(--_track-size) / 4), 3px);

  color: white;
  font-size: calc(var(--_track-size) / 1.25);
}

Screenshot des Ladebalkens bei 100% mit einem Häkchen am Ende

Farbe

Der Browser verwendet eigene Farben für das Fortschrittselement und ist anpassungsfähig, „Hell“ und „Dunkel“ mit nur einer CSS-Eigenschaft. Dies kann mit einigen spezielle browserspezifische Selektoren.

Helle und dunkle Browserstile

So aktivierst du auf deiner Website ein adaptives <progress>-Element mit dunklem und hellem Design: Sie brauchen nur color-scheme.

progress {
  color-scheme: light dark;
}

Füllfarbe des Fortschritts einer einzelnen Unterkunft

Verwende accent-color, um ein <progress>-Element zu färben.

progress {
  accent-color: rebeccapurple;
}

Beachten Sie, dass sich die Hintergrundfarbe der Spur von hell zu dunkel wechselt, je nachdem, accent-color Der Browser sorgt für einen angemessenen Kontrast: ziemlich übersichtlich.

Vollständig benutzerdefinierte helle und dunkle Farben

Legen Sie zwei benutzerdefinierte Eigenschaften für das <progress>-Element fest, eine für die Track-Farbe. und die andere für die Farbe des Fortschritts. Im Inneren der prefers-color-scheme Medienabfrage eingeben, neue Farbwerte für den Titel angeben und den Fortschritt verfolgen.

progress {
  --_track: hsl(228 100% 90%);
  --_progress: hsl(228 100% 50%);
}

@media (prefers-color-scheme: dark) {
  progress {
    --_track: hsl(228 20% 30%);
    --_progress: hsl(228 100% 75%);
  }
}

Fokusstile

Wir haben dem Element bereits einen negativen Tabindex zugewiesen, damit es programmatisch fokussiert sind. Verwenden Sie :focus-visible bis Passe den Fokus an, um den intelligenten Fokusring zu aktivieren. Dabei wird eine Maus wird der Fokus nicht angezeigt, Klicks über die Tastatur jedoch schon. Die In YouTube-Videos wird dies ausführlicher beschrieben. eine Überprüfung lohnen.

progress:focus-visible {
  outline-color: var(--_progress);
  outline-offset: 5px;
}

Screenshot der Ladeleiste mit einem Fokusring darum Alle Farben stimmen überein.

Benutzerdefinierte Stile für verschiedene Browser

Passen Sie die Stile an, indem Sie die Teile eines <progress>-Elements auswählen, die jeweils die der Browser freigibt. Das progress -Element wird als einzelnes Tag verwendet, Einige untergeordnete Elemente, die über CSS-Pseudoselektoren bereitgestellt werden. Chrome-Entwicklertools werden folgende Elemente angezeigt, wenn Sie die Einstellung aktivieren:

  1. Klicke mit der rechten Maustaste auf deine Seite und wähle Inspect Element aus, um die Entwicklertools aufzurufen.
  2. Klicken Sie oben rechts im Entwicklertools-Fenster auf das Zahnradsymbol für die Einstellungen.
  3. Aktivieren Sie unter der Überschrift Elements die Option Elements. DOM.

Screenshot dazu, wo in den Entwicklertools das Verfügbarmachen des User-Agent-Shadow-DOM aktiviert werden kann.

Safari- und Chromium-Stile

WebKit-basierte Browser wie Safari und Chromium veröffentlichen ::-webkit-progress-bar und ::-webkit-progress-value, die eine Teilmenge von Zu verwendendes CSS. Legen Sie background-color vorerst mithilfe der benutzerdefinierten Eigenschaften fest die sich an Helligkeit und Dunkelheit anpassen.

/*  Safari/Chromium  */
progress[value]::-webkit-progress-bar {
  background-color: var(--_track);
}

progress[value]::-webkit-progress-value {
  background-color: var(--_progress);
}

Screenshot mit den inneren Elementen des „progress“-Elements

Firefox-Stile

Firefox zeigt nur den Pseudoselektor ::-moz-progress-bar auf der <progress>-Element. Das bedeutet auch, dass wir den Titel nicht direkt färben können.

/*  Firefox  */
progress[value]::-moz-progress-bar {
  background-color: var(--_progress);
}

Screenshot von Firefox und Informationen dazu, wo Sie die Bestandteile des Fortschrittselements finden

Screenshot des Debugging Corner, in dem Safari, iOS Safari, 
  In Firefox, Chrome und Chrome unter Android wird die Ladeleiste angezeigt.

Beachten Sie, dass in Firefox in Safari für iOS die Track-Farbe auf accent-color eingestellt ist. eine hellblaue Spur. Das Gleiche gilt im dunklen Modus: Firefox hat eine dunkle Spur, und nicht die von uns festgelegte benutzerdefinierte Farbe. Sie funktioniert in WebKit-basierten Browsern.

Animation

Bei der Arbeit mit im Browser integrierten Pseudoselektoren ist dies häufig mit der zulässigen CSS-Eigenschaften.

Animation der Strecke, die sich füllt

Durch Hinzufügen eines Übergangs zum inline-size von Das progress-Element funktioniert für Chromium, aber nicht für Safari. Firefox kann auch kein Übergangsattribut für ::-moz-progress-bar.

/*  Chromium Only 😢  */
progress[value]::-webkit-progress-value {
  background-color: var(--_progress);
  transition: inline-size .25s ease-out;
}

Status :indeterminate animieren

Hier werde ich etwas kreativer, damit ich eine Animation bereitstellen kann. Ein Pseudoelement für Chromium erstellt und ein Farbverlauf angewendet wird, für alle drei Browser.

Benutzerdefinierte Eigenschaften

Benutzerdefinierte Eigenschaften eignen sich für viele Dinge, aber einer meiner Favoriten einem ansonsten magisch aussehenden CSS-Wert einen Namen geben. Es ist ziemlich einfach, komplex linear-gradient, aber mit einem hübschen Namen. Sein Zweck und seine Anwendungsfälle sind klar nachvollziehbar.

progress {
  --_indeterminate-track: linear-gradient(to right,
    var(--_track) 45%,
    var(--_progress) 0%,
    var(--_progress) 55%,
    var(--_track) 0%
  );
  --_indeterminate-track-size: 225% 100%;
  --_indeterminate-track-animation: progress-loading 2s infinite ease;
}

Benutzerdefinierte Eigenschaften tragen auch dazu bei, dass der Code DRY bleibt, da wir wieder keine können Sie diese browserspezifischen Selektoren gruppieren.

Die Keyframes

Das Ziel ist eine unendliche Animation, die hin und her wechselt. Anfang und Ende werden in CSS festgelegt. Es ist nur ein Keyframe erforderlich: der mittlere Keyframe. um 50%, um eine Animation zu erstellen, immer wieder neu!

@keyframes progress-loading {
  50% {
    background-position: left; 
  }
}

Targeting auf jeden Browser

Nicht in jedem Browser können Pseudoelemente im <progress> erstellt werden. Element selbst oder ermöglicht das Animieren der Fortschrittsanzeige. Weitere Browserunterstützung statt eines Pseudoelements. Daher führe ich ein Upgrade von Pseudoelementen als als Basis und in Animationsbalken.

Chromium-Pseudoelement

Chromium lässt das Pseudoelement „::after“ mit einer abzudeckenden Position zu. das Element. Die unbestimmten benutzerdefinierten Eigenschaften werden verwendet, der vierten Animation funktioniert.

progress:indeterminate::after {
  content: "";
  inset: 0;
  position: absolute;
  background: var(--_indeterminate-track);
  background-size: var(--_indeterminate-track-size);
  background-position: right; 
  animation: var(--_indeterminate-track-animation);
}
Safari-Fortschrittsanzeige

In Safari werden die benutzerdefinierten Eigenschaften und eine Animation auf das Fortschrittsanzeige für Pseudoelement:

progress:indeterminate::-webkit-progress-bar {
  background: var(--_indeterminate-track);
  background-size: var(--_indeterminate-track-size);
  background-position: right; 
  animation: var(--_indeterminate-track-animation);
}
Firefox-Fortschrittsanzeige

In Firefox werden die benutzerdefinierten Eigenschaften und eine Animation auch auf das Fortschrittsanzeige für Pseudoelement:

progress:indeterminate::-moz-progress-bar {
  background: var(--_indeterminate-track);
  background-size: var(--_indeterminate-track-size);
  background-position: right; 
  animation: var(--_indeterminate-track-animation);
}

JavaScript

JavaScript spielt beim <progress>-Element eine wichtige Rolle. Sie steuert Wert, der an das Element gesendet wird, und stellt sicher, dass genügend Informationen im für Screenreader.

const state = {
  val: null
}

Die Demo enthält Schaltflächen zur Steuerung des Fortschritts: sie/er aktualisiert state.val und dann eine Funktion zum Aktualisieren der DOM enthält.

document.querySelector('#complete').addEventListener('click', e => {
  state.val = 1
  setProgress()
})

setProgress()

In dieser Funktion findet die UI/UX-Orchestrierung statt. Erstellen Sie als Erstes ein setProgress(). Es sind keine Parameter erforderlich, da sie Zugriff auf die state-Objekt, Fortschrittselement und <main>-Zone.

const setProgress = () => {
  
}

Ladestatus für die Zone <main> festlegen

Je nachdem, ob der Fortschritt abgeschlossen ist oder nicht, werden die entsprechenden <main> -Element erfordert ein Update des aria-busy Attribut:

const setProgress = () => {
  zone.setAttribute('aria-busy', state.val < 1)
}

Attribute löschen, wenn der Ladebetrag unbekannt ist

Wenn der Wert unbekannt oder nicht konfiguriert ist, null bei dieser Verwendung, entfernen Sie value und aria-valuenow-Attribute. Dadurch wird <progress> in „Unbestimmt“ geändert.

const setProgress = () => {
  zone.setAttribute('aria-busy', state.val < 1)

  if (state.val === null) {
    progress.removeAttribute('aria-valuenow')
    progress.removeAttribute('value')
    progress.focus()
    return
  }
}

Probleme mit Dezimalzahlen in JavaScript beheben

Da ich mich für den Standardwert von 1 für den Fortschritt entschieden habe, Für Inkrement- und Dekrement-Funktionen werden Dezimalzahlen verwendet. JavaScript und andere Sprachen nicht immer gut . Hier ist eine roundDecimals()-Funktion, mit der überflüssige Berechnungen reduziert werden. Ergebnis:

const roundDecimals = (val, places) =>
  +(Math.round(val + "e+" + places)  + "e-" + places)

Runden Sie den Wert, damit er angezeigt werden kann und lesbar ist:

const setProgress = () => {
  zone.setAttribute('aria-busy', state.val < 1)

  if (state.val === null) {
    progress.removeAttribute('aria-valuenow')
    progress.removeAttribute('value')
    progress.focus()
    return
  }

  const val = roundDecimals(state.val, 2)
  const valPercent = val * 100 + "%"
}

Wert für Screenreader und Browserstatus festlegen

Der Wert wird an drei Stellen im DOM verwendet:

  1. Das value-Attribut des <progress>-Elements.
  2. Das Attribut aria-valuenow.
  3. Der innere Textinhalt <progress>.
const setProgress = () => {
  zone.setAttribute('aria-busy', state.val < 1)

  if (state.val === null) {
    progress.removeAttribute('aria-valuenow')
    progress.removeAttribute('value')
    progress.focus()
    return
  }

  const val = roundDecimals(state.val, 2)
  const valPercent = val * 100 + "%"

  progress.value = val
  progress.setAttribute('aria-valuenow', valPercent)
  progress.innerText = valPercent
}

Den Fortschritt in den Fokus rücken

Wenn die Werte aktualisiert wurden, sehen sehende Nutzer zwar den Fortschritt, Leser wurden noch nicht über die Änderung informiert. Fokus auf die <progress>-Element und der Browser kündigt das Update an.

const setProgress = () => {
  zone.setAttribute('aria-busy', state.val < 1)

  if (state.val === null) {
    progress.removeAttribute('aria-valuenow')
    progress.removeAttribute('value')
    progress.focus()
    return
  }

  const val = roundDecimals(state.val, 2)
  const valPercent = val * 100 + "%"

  progress.value = val
  progress.setAttribute('aria-valuenow', valPercent)
  progress.innerText = valPercent

  progress.focus()
}

Screenshot der Voice Over-App unter Mac OS 
  dem Nutzer den Fortschritt des Ladebalkens.

Fazit

Jetzt, wo du weißt, wie ich es gemacht habe, wie würdest du... ‽ 🙂

Es gibt sicherlich ein paar Änderungen, die ich gerne vornehmen würde, wenn ich noch eine Gelegenheit dazu hätte. Ich denke, es ist Raum, die aktuelle Komponente zu bereinigen, und Raum, eine ohne die Stilbeschränkungen der Pseudoklasse des <progress>-Elements zu erstellen. Es lohnt sich!

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