Présentation générale de la création d'une barre de chargement accessible et adaptable aux couleurs avec l'élément <progress>
.
Dans ce post, je vais vous expliquer comment créer
accessible via l'élément <progress>
. Essayez le
une démonstration et regardez la
.
Si vous préférez la vidéo, voici une version YouTube de cet article:
Présentation
La
<progress>
fournit aux utilisateurs un retour visuel et audio sur l'achèvement. Ce
un retour visuel est utile pour des scénarios
tels que la progression dans un formulaire,
afficher des informations de téléchargement ou d'importation, ou même indiquer
la quantité de progression est inconnue, mais la tâche est toujours active.
Ce défi de l'IUG a collaboré avec
l'élément HTML <progress>
existant pour simplifier l'accessibilité. La
les couleurs et les mises en page repoussent les limites de la personnalisation de l'élément intégré, pour
de moderniser le composant et de le faire
mieux s'intégrer dans les systèmes de conception.
Majoration
J'ai choisi d'encapsuler l'élément <progress>
dans une
<label>
ainsi
Je pourrais ignorer les attributs de relation explicites au profit d'un modèle implicite
relationnel.
J'ai également étiqueté un élément parent
affecté par l'état de chargement, donc l'écran
les technologies de lecture peuvent transmettre
ces informations à un utilisateur.
<progress></progress>
Si aucun value
ne s'affiche, la progression de l'élément est
indéterminée.
La valeur par défaut de l'attribut max
est 1. La progression est donc comprise entre 0 et 1. Définir max
sur 100, par exemple, définit la plage sur 0-100. J'ai choisi de rester dans la
et 1, ce qui traduit les valeurs de progression à 0,5 ou 50%.
Progression de l'encapsulation par étiquette
Dans une relation implicite, un élément de progression est encapsulé par un libellé semblable à celui-ci:
<label>Loading progress<progress></progress></label>
Dans ma démonstration, j'ai choisi d'inclure le libellé correspondant aux lecteurs d'écran
uniquement.
Pour ce faire, encapsulez le texte du libellé dans une <span>
et appliquez des styles.
pour qu'elle soit
en dehors de l'écran:
<label>
<span class="sr-only">Loading progress</span>
<progress></progress>
</label>
Avec le code CSS suivant de WebAIM associé:
.sr-only {
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
}
Zone affectée par la progression du chargement
Si votre vision est saine, vous pouvez facilement associer un indicateur de progression
avec des éléments et des zones de page connexes, mais pour les utilisateurs malvoyants,
si clair. Pour améliorer cela, attribuez
aria-busy
à l'élément de niveau supérieur qui changera une fois le chargement terminé.
De plus, indiquer une relation entre la progression et la zone de chargement
par
aria-describedby
<main id="loading-zone" aria-busy="true">
…
<progress aria-describedby="loading-zone"></progress>
</main>
À partir de JavaScript, basculez aria-busy
sur true
au début de la tâche et sur
false
.
Ajouts d'attributs Aria
Alors que le rôle implicite d'un élément <progress>
est
progressbar
, le contenu est explicite
pour les navigateurs qui n'ont pas ce rôle implicite. J'ai également ajouté l'attribut
indeterminate
pour placer explicitement l'élément dans un état inconnu, à savoir
plus claire que d'observer l'élément sans value
défini.
<label>
Loading
<progress
indeterminate
role="progressbar"
aria-describedby="loading-zone"
tabindex="-1"
>unknown</progress>
</label>
Utilisez
tabindex="-1"
pour que l'élément de progression puisse être sélectionné à partir de JavaScript. Ceci est important pour
la technologie de lecteur d'écran, car en donnant
l'accent sur la progression au fur et à mesure que la progression évolue,
annoncera à l'utilisateur l'état d'avancement de la mise à jour.
Styles
L'élément de progression est un peu complexe au niveau du style. HTML intégré les éléments comportent des parties cachées spéciales qui peuvent être difficiles à sélectionner et souvent ne proposent qu'un ensemble limité de propriétés à définir.
Mise en page
Les styles de mise en page sont conçus pour permettre une certaine flexibilité dans la progression la taille et la position du libellé de l'élément. Un état d'achèvement spécial est ajouté qui peut être un indice visuel supplémentaire utile, mais non obligatoire.
Mise en page <progress>
La largeur de l'élément de progression reste inchangée afin qu'elle puisse être réduite et agrandie.
avec l'espace nécessaire
dans la conception. Les styles intégrés sont supprimés
en définissant appearance
et border
sur none
. Cela est fait pour que
l'élément puisse être
sont normalisés entre les navigateurs, car chacun a son propre style pour ses
.
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;
}
La valeur de 1e3px
pour _radius
utilise un numéro scientifique
pour exprimer un
un grand nombre de sorte que border-radius
soit toujours arrondi. Cela équivaut à
1000px
J'aime l'utiliser, car mon objectif est
d'utiliser une valeur suffisamment élevée pour
Je peux le définir et l'oublier (et son écriture est plus court que 1000px
). Il est également
Il est facile de les agrandir si nécessaire: remplacez simplement 3 par 4, et 1e4px
sera
équivalente à 10000px
.
overflow: hidden
est utilisé et constitue un style litigieux. Quelques
les choses. Par exemple, il n'est pas nécessaire de transmettre les valeurs border-radius
à la
suivre et suivre les éléments de remplissage ; mais il fallait également qu'il n'y ait aucun enfant du progrès
pourraient vivre en dehors de l'élément. Une autre itération de cette progression personnalisée
l'élément peut être effectué sans overflow: hidden
et risque d'ouvrir
des animations ou de meilleurs états de fin.
Processus terminé
Dans ce cas, les sélecteurs CSS sont les plus complexes en comparant le maximum à la valeur. Si ces valeurs correspondent, la progression est terminée. Une fois l'opération terminée, un pseudo-élément est généré et ajouté à la fin de l'élément de progression, ce qui constitue un indicateur visuel supplémentaire de la fin de l'opération.
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);
}
Couleur
Le navigateur applique ses propres couleurs pour l'élément de progression et s'adapte à clair et sombre à l'aide d'une seule propriété CSS. Vous pouvez vous appuyer sur certaines des sélecteurs spéciaux propres au navigateur.
Styles de navigateur clair et sombre
Pour activer l'élément <progress>
adaptatif sombre et clair sur votre site, procédez comme suit :
color-scheme
est tout ce qu'il vous faut.
progress {
color-scheme: light dark;
}
Couleur remplie de la progression d'une propriété unique
Pour colorer un élément <progress>
, utilisez accent-color
.
progress {
accent-color: rebeccapurple;
}
Notez que la couleur d'arrière-plan de la piste passe du clair au foncé
accent-color
Le navigateur assure le contraste, ce qui est plutôt net.
Couleurs claires et sombres entièrement personnalisées
Définissez deux propriétés personnalisées sur l'élément <progress>
, l'une pour la couleur de la piste.
et l'autre pour la couleur du suivi de la progression. Au cœur de la
prefers-color-scheme
requête média, fournissez de nouvelles valeurs de couleur pour le titre et suivez la progression.
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%);
}
}
Styles de focus
Nous avons précédemment attribué à l'élément un index d'onglet négatif afin qu'il puisse être programmatique.
concentré. Utilisez
:focus-visible
jusqu'à
Personnalisez la mise au point pour activer le style de l'anneau de mise au point plus intelligent. Avec cela, une souris
les clics et le focus n'affichent pas l'anneau de focus, contrairement aux clics du clavier. La
Vidéo YouTube approfondit ce sujet.
mérite d'être examiné.
progress:focus-visible {
outline-color: var(--_progress);
outline-offset: 5px;
}
Styles personnalisés dans les différents navigateurs
Personnalisez les styles en sélectionnant les parties d'un élément <progress>
qui correspondent chacune
le navigateur expose. L'élément Progress utilisé est une balise unique, mais elle est constituée d'un
quelques éléments enfants exposés via des sélecteurs de pseudo CSS. Outils pour les développeurs Chrome
affiche les éléments suivants si vous activez ce paramètre:
- Effectuez un clic droit sur votre page, puis sélectionnez Inspect Element (Inspecter l'élément) pour afficher les outils de développement.
- Cliquez sur l'icône en forme de roue dentée des paramètres en haut à droite de la fenêtre "DevTools".
- Sous l'en-tête Elements, recherchez et activez l'option Afficher l'ombre user-agent DOM.
Styles Safari et Chromium
Les navigateurs basés sur WebKit tels que Safari et Chromium exposent
::-webkit-progress-bar
et ::-webkit-progress-value
, qui permettent à un sous-ensemble
CSS à utiliser. Pour l'instant, définissez background-color
à l'aide des propriétés personnalisées
créées précédemment, qui s'adaptent à la lumière et à l'obscurité.
/* Safari/Chromium */
progress[value]::-webkit-progress-bar {
background-color: var(--_track);
}
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
}
Styles Firefox
Firefox n'expose que le pseudo-sélecteur ::-moz-progress-bar
au niveau du
Élément <progress>
. Cela signifie également que nous ne pouvons pas teindre directement la piste.
/* Firefox */
progress[value]::-moz-progress-bar {
background-color: var(--_progress);
}
Notez que la couleur de suivi est définie sur accent-color
pour Firefox et Safari pour iOS.
présente une ligne bleu clair. Il en va de même en mode sombre: Firefox a une piste sombre, mais
pas la couleur personnalisée que nous avons définie, et cela fonctionne
dans les navigateurs basés sur WebKit.
Animation
Lorsque vous travaillez avec des pseudo-sélecteurs intégrés au navigateur, d'un ensemble de propriétés CSS autorisées.
Animer la piste qui se remplit
Ajouter une transition au
inline-size
sur
l'élément de progression fonctionne dans Chromium, mais pas dans Safari. Firefox fait aussi
n'utilisez pas de propriété de transition sur ::-moz-progress-bar
.
/* Chromium Only 😢 */
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
transition: inline-size .25s ease-out;
}
Animer l'état :indeterminate
Ici, je suis un peu plus créatif et je peux proposer une animation. Un pseudo-élément pour Chromium est créé, et un dégradé est appliqué, qui est animé en arrière et pour les trois navigateurs.
Propriétés personnalisées
Les propriétés personnalisées conviennent à de nombreux besoins, mais l'une de mes préférées
pour donner un nom à une valeur CSS tout à fait magique. Le contenu suivant est une
complexe
linear-gradient
,
mais avec un joli nom. Son objectif et ses cas d'utilisation doivent être clairement compris.
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;
}
Les propriétés personnalisées permettent également au code de rester DRY, car il est impossible vous pouvez regrouper ces sélecteurs spécifiques au navigateur.
Les images clés
L'objectif est une animation infinie qui va dans les deux sens. Le début et la fin
les images clés sont définies dans CSS. Une seule image clé est nécessaire : celle du milieu
à 50%
, pour créer une animation qui revient à son point de départ,
encore une fois !
@keyframes progress-loading {
50% {
background-position: left;
}
}
Cibler chaque navigateur
Tous les navigateurs n'autorisent pas la création de pseudo-éléments sur le <progress>
lui-même ou autorise l'animation de la barre de progression. Compatibilité avec d'autres navigateurs
pour animer la piste plutôt qu'un pseudo-élément.
une base et en barres d’animation.
Pseudo-élément Chromium
Chromium autorise le pseudo-élément: ::after
, utilisé avec une position de couverture.
de l'élément. Les propriétés personnalisées indéterminées sont utilisées, et le retour et
l'animation suivante fonctionne très bien.
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);
}
Barre de progression Safari
Dans Safari, les propriétés personnalisées et une animation sont appliquées au Barre de progression pseudo-élément:
progress:indeterminate::-webkit-progress-bar {
background: var(--_indeterminate-track);
background-size: var(--_indeterminate-track-size);
background-position: right;
animation: var(--_indeterminate-track-animation);
}
Barre de progression Firefox
Pour Firefox, les propriétés personnalisées et une animation sont également appliquées à la Barre de progression pseudo-élément:
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 joue un rôle important avec l'élément <progress>
. Contrôle
la valeur envoyée à l'élément et s'assure que le champ
pour les lecteurs d'écran.
const state = {
val: null
}
La démo propose des boutons permettant de contrôler la progression. ils mettent à jour state.val
puis d'appeler une fonction pour mettre à jour
DOM
document.querySelector('#complete').addEventListener('click', e => {
state.val = 1
setProgress()
})
setProgress()
C'est dans cette fonction que s'effectue l'orchestration de l'UI/de l'expérience utilisateur. Commencez par créer un
fonction setProgress()
. Aucun paramètre n'est requis, car l'instance a accès au
Objet state
, élément de progression et zone <main>
.
const setProgress = () => {
}
Définir l'état de chargement sur la zone <main>
Selon que la progression est terminée ou non, le <main>
associé
doit être mis à jour
aria-busy
attribut:
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
}
Effacer les attributs si la quantité de chargement est inconnue
Si la valeur est inconnue ou n'est pas définie, null
dans cette utilisation, supprimez value
et
aria-valuenow
. Cela transformera <progress>
en indéterminé.
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
}
Résoudre les problèmes de mathématiques décimales JavaScript
Comme j'ai choisi de conserver la progression par défaut (1),
les fonctions d'incrémentation et de décrémentation
utilisent des calculs décimaux. JavaScript et autres
langues, ne sont pas toujours doués pour
de sécurité.
Voici une fonction roundDecimals()
qui supprime l'excès de la formule mathématique
résultat:
const roundDecimals = (val, places) =>
+(Math.round(val + "e+" + places) + "e-" + places)
Arrondissez la valeur de façon à ce qu'elle soit présentée et lisible:
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 + "%"
}
Définir la valeur pour les lecteurs d'écran et l'état du navigateur
Cette valeur est utilisée à trois emplacements dans le DOM:
- L'attribut
value
de l'élément<progress>
. - L'attribut
aria-valuenow
- Le contenu textuel interne de
<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
}
Cibler la progression
Une fois les valeurs mises à jour, les utilisateurs voyants verront la progression changer, mais l’écran
les utilisateurs de lecteurs ne sont pas encore informés de ce changement. Sélectionnez
<progress>
et le navigateur annoncera la mise à jour.
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()
}
Conclusion
Maintenant que vous savez comment j'ai fait, comment feriez-vous ? 😃
Il y a certainement quelques modifications que j'aimerais apporter si je me permets de vous laisser le temps. Je pense qu'il est possible de nettoyer le composant actuel et d'en créer un sans les limites de style de pseudo-classe de l'élément <progress>
. Cela vaut la peine d'être exploré !
Diversifiez nos approches et découvrons toutes les manières de créer des applications sur le Web.
Créer une démonstration, me envoyer des tweets et je l'ajouterai à la section des remix de la communauté ci-dessous.