Een gestileerde voortgangsbalk maken

Het element <progress> is de semantische manier om de voortgang van een taak weer te geven, zoals het downloaden of uploaden van informatie of het afronden van een deel van een proces met meerdere stappen. Het gebruik van het systeemeigen element helpt bij de toegankelijkheid, omdat schermlezers een impliciete role="progressbar" hebben en waarden kunnen aankondigen.

In deze handleiding wordt een volledig opgemaakte horizontale voortgangsbalk met stijlaanpassingen geïmplementeerd.

Voortgangsbalk of voortgangsring?

  • Als de ruimte beperkt is of een vierkante beeldverhouding de voorkeur heeft, kun je een cirkelvormige voortgangsbalk (voortgangsring) gebruiken: Voortgangsring
  • Gebruik spinners voor de meeste scenario's met onbepaalde voortgang (Laadspinner). Gebruik onbepaalde voortgangsbalken als de onbepaalde status tijdelijk is en binnenkort wordt vervangen door een bepaalde voortgangsbalk (bijvoorbeeld als je wacht op metadata rond een upload voordat een voortgangspercentage kan worden getoond)

Opmaak

  1. Gebruik een native <progress>-element: Dit biedt ingebouwde toegankelijkheid en platformconsistent gedrag.
  2. Gebruik max als je een andere schaal dan de standaardschaal 0-1 nodig hebt.
  3. Stel een kenmerk value in voor een specifieke voortgangswaarde. Laat value weg voor een onbepaalde status (bijvoorbeeld voordat er concretere feedback begint).
  4. Gebruik <label for="...">, aria-labelledby of aria-label om het voortgangselement aan een label te koppelen.

Wat voor aanpassing is er nodig?

Voor beperkte opmaak zijn deze eigenschappen voldoende:

  • accent-color om de kleur van de voortgangsbalk te wijzigen
  • width / inline-size om de breedte van de voortgangsbalk te wijzigen
  • height/block-size wordt inconsistent toegepast: test eerst
  • writing-mode: vertical-lr voor verticale staven.
  • Effecten die worden toegepast na het tekenen: opacity, filter, clip-path, maskers, transformaties, box-shadow, enzovoort.

Als beperkte stijlopties voldoende zijn, slaat u het volgende gedeelte over.

WAARSCHUWING: Bepaalde eigenschappen (bijv. border-radius, background, border) zetten de standaardstijl van de voortgangsbalk zonder melding uit. Als u meer aangepaste stijl nodig heeft dan de bovenstaande eigenschappen, moet u een volledig aangepaste opmaak implementeren, zoals beschreven in het volgende gedeelte. Pas GEEN uitgebreidere opmaak toe 'voor het geval het werkt'.

Volledig aangepaste stijl

1. Basisinstellingen

  • VERPLICHT: Gebruik appearance: none om aangepaste stijl aan te zetten.
  • UA-grenzen resetten met border: 0 solid
  • Als je de actieve balk wilt inkorten tot de border-radius van het element, gebruik je overflow: clip OF pas je dezelfde border-radius toe op de balk. Gebruik border-radius: inherit NIET op de balk, omdat dit afhankelijk is van de specifieke structuur van elementen in de shadow DOM.
progress {
  /* Reset default browser styles */
  appearance: none;
  border: 0 solid;
  /* Clip bar to element’s border-radius  */
  overflow: clip;
}

2. Stijl

  • Stijl de track op het progress-element zelf.
  • Gebruik het juiste browsergerichte pseudo-element om de voortgangsbalk zelf te targeten: ::-webkit-progress-value voor WebKit/Blink en ::-moz-progress-bar voor Firefox.
  • VERPLICHT: Groepeer de pseudoelementen -webkit- en -moz- NIET in dezelfde regel. De regel wordt als ongeldig beschouwd en wordt genegeerd. :is() en :where() helpen hier niet, omdat ze geen pseudo-elementen ondersteunen.
  • Elk op de browser getarget pseudoelement mag maar één keer voorkomen. Staatspecifieke aanpassingen (zoals de onbepaalde segmentgrootte en animatie) moeten worden gerouteerd via aangepaste eigenschappen die zijn ingesteld op het element progress zelf.
  • Optioneel: Overgang inline-size op de vulling, zodat wijzigingen in de bepaalde waarde worden geanimeerd in plaats van dat ze verspringen. Firefox past de grootte van de opvulling aan de indeling aan en negeert deze, wat onschadelijk is.
progress {
  --progress-bar-radius: 1e5px;
  border-radius: var(--progress-bar-radius);
  /* Apply color for custom progress track (background) */
  background: var(--progress-bar-track, var(--color-neutral-90));
  /* Subtle depth on the empty part of the track */
  box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);
}

/* Let <progress> styling show through */
progress::-webkit-progress-bar {
  background: transparent;
}

/* Webkit, Chrome */
progress::-webkit-progress-value {
  background: var(--progress-bar-fill, var(--accent-color));
  border-radius: var(--progress-bar-radius);
  transition: inline-size 0.3s;
}

/* Firefox */
progress::-moz-progress-bar {
  background: var(--progress-bar-fill, var(--accent-color));
  border-radius: var(--progress-bar-radius);
  transition: inline-size 0.3s;
}

3. Stijl voor onbepaalde status

Voeg een aangepaste animatie toe voor de onbepaalde status: Maak van het pseudo-element voor vulling een kort segment en schuif het over de track.

  • Stijl de vulling zelf. Maak deze NIET opnieuw als achtergrond op progress.
  • De onbepaalde vulling bestaat alleen via de animatie: de keyframes stellen de lengte in met een echte inline-size (dit is beter dan de UA-inline inline-size van Chromium) en verplaatsen deze met translate. Gebruik NIET scale voor de lengte. Dit vervormt het patroon dat op de vulling is geschilderd.
  • translate-percentages worden opgelost op basis van de eigen breedte van de opvulling. Druk posities daarom uit in trackeenheden: maak van progress een inline-size-container en gebruik cqi in de keyframes. Neem margin-right: auto op in from, to, zodat Chromium de opvulling ook fysiek links plaatst in RTL.
  • Gebruik transformaties, geen marges, om de opvulling te verplaatsen.
    • Transformaties houden de animatie in de compositor (tenzij inline-size ook wordt geanimeerd)
    • Marges worden verbroken in RTL, om 2 verschillende redenen:
    • Firefox positioneert de onbepaalde vulling alleen met de fysieke linkermarge, dus margin-inline-start heeft geen effect in RTL en de vulling wordt nooit verplaatst.
    • In Chromium en WebKit, die de vulling als een normaal blok opmaken, tellen de marges op tot meer dan de track zodra een marge de vulling voorbij het einde van de track duwt. Standaard-CSS lost dit op door margin-left te negeren in RTL, zodat het segment naar de rand springt in plaats van eraf te schuiven.
    • translate wordt toegepast na de opmaak, dus geen van beide problemen is van toepassing.
  • Als je de beweging wilt spiegelen in RTL (zoals de systeembalk van Chrome doet), draai je de animatie om onder :dir(rtl):
progress:dir(rtl) {
  --progress-bar-indeterminate-animation: progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear reverse;
}
  • Definieer de openbare --progress-bar-indeterminate-*-eigenschappen op progress (hun naam beperkt ze al tot de status) zodat consumenten ze kunnen overschrijven zonder iets te weten over :indeterminate.
  • Als je de segmentlengte wilt variëren (bijvoorbeeld de voorrand gaat vooruit en de achterrand haalt deze in), stel je --progress-bar-indeterminate-animation in op 2 gelijktijdige animaties: een waarvan de keyframes translate animeren in cqi (positie) en een waarvan de keyframes inline-size animeren (lengte), zodat elk zijn eigen keyframes en easing krijgt. Probeer NIET om beide randen vorm te geven in één lijst met sleutelframes. animation-timing-function per sleutelframe is van toepassing op elke eigenschap in dat sleutelframe.
  • --progress-bar-animation is van toepassing in beide statussen en kan worden gebruikt voor effecten zoals een bepaalde glinstering. revert-rule wordt gebruikt om alleen te overschrijven als deze is ingesteld, om de samenstelbaarheid te maximaliseren.
  • Zet de onbepaalde animatie nooit uit (animation: none laat een vulling van nul breedte achter in Chromium). Voor minder beweging kun je de video vertragen.
progress {
  /* Lets the fill position itself in track units (cqi) */
  container-type: inline-size;
  /* Segment length relative to the track */
  --progress-bar-indeterminate-size: 30%;
  --progress-bar-indeterminate-animation-duration: 1.5s;

  /* Respect prefers-reduced-motion */
  @media (prefers-reduced-motion: reduce) {
    --progress-bar-indeterminate-animation-duration: 10s;
  }
}

progress:indeterminate {
  --progress-bar-animation: var(
      --progress-bar-indeterminate-animation,
      progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear
    );
}

/* Add to the existing pseudo-element rules */
progress::-webkit-progress-value {
  animation: var(--progress-bar-animation, revert-rule);
}

progress::-moz-progress-bar {
  animation: var(--progress-bar-animation, revert-rule);
}

/* Physical: left to right regardless of direction (reverse under :dir(rtl) to mirror). */
@keyframes progress-bar-indeterminate {
  from, to {
    inline-size: var(--progress-bar-indeterminate-size);
    /* Pin to the physical left; Chromium would otherwise lay the fill out at the inline start */
    margin-right: auto;
  }
  from { translate: -100%; } /* Own width: fully outside the left edge */
  to { translate: 100cqi; }  /* Track width: fully outside the right edge */
}

Aanvullende overwegingen voor toegankelijkheid

Naast de hierboven genoemde richtlijnen:

  • Kondig de voltooiing aan zonder de focus te stelen: Stel tabindex niet in en roep .focus() niet aan op <progress>, omdat dit niet-interactief is en de focus verplaatsen naar dit element toetsenbordgebruikers verstoort. Als je wilt aankondigen wanneer een achtergrondtaak is afgerond, update je een beleefd statuselement (role="status" of aria-live="polite").
  • Voeg geen fallback-tekst toe aan <progress>: Tekst in <progress> wordt genegeerd door moderne browsers en wordt niet gebruikt door ondersteunende technologieën.
  • Vermijd aria-busy + aria-describedby op een niet-gelabelde algemene <div>. aria-busy heeft inconsistente ondersteuning voor schermlezers en aria-describedby op een naamloze <div> zonder rol wordt genegeerd door ondersteunende technologieën. Als de content van een regio niet klaar is tijdens het laden, verberg je deze met hidden of aria-hidden="true".
  • ZORG voor een goed contrast tussen de voortgangsbalk en de track als je aangepaste stijlen toevoegt.
  • Overweeg alternatieven om een onbepaalde status weer te geven: Animaties van een onbepaalde voortgangsbalk die parallel aan andere content worden getoond, kunnen voor sommige gebruikers als afleidend worden beschouwd.

Reservestrategieën

Fallbacks en browserondersteuning voor accent-color

De property accent-color is progressive enhancement. Browsers die deze property niet ondersteunen, negeren deze en gebruiken de standaard UI-kleuren.

Als accent-color niet wordt ondersteund en de voortgangsbalk moet worden opgemaakt, gebruikt u de aangepaste opmaakmethode om de gewenste opmaak toe te passen op de voortgangsbalk.

Fallbacks en browserondersteuning voor revert-rule

Als revert-rule niet wordt ondersteund, valt animation: var(--progress-bar-animation, revert-rule) terug op animation-name: revert-rule met een duur van 0s als --progress-bar-animation niet is ingesteld. Dit is een onschadelijke no-op als er geen @keyframes revert-rule bestaat.