Comment créer une barre de progression réactive et dynamique avec HTML, CSS et JavaScript

Il y a quelques années, j'ai écrit un court article sur la création d'une barre de progression réactive. Mes techniques se sont développées depuis, et donc une mise à jour s'impose.

Le plus gros changement est que les pseudo-éléments (avant, après) ne sont plus nécessaires. Maintenant, le CSS est plus simple, le DOM est plus facile à lire et il est beaucoup plus dynamique.

Alors essayons à nouveau.

Notre objectif est de créer une barre de progression réactive simple et efficace qui effectue les opérations suivantes:

  • A quatre étapes à compléter.
  • Chaque étape a default, activeet l' completeÉtat.
  • Peut progresser d'une étape à l'autre jusqu'à la fin.

Consultez le CodePen ici pour un exemple en direct.

Le HTML

Pour réduire la redondance et augmenter la réutilisabilité, nous suivons tous les états d'un composant Vue. Dans le DOM, cela génère dynamiquement n'importe quel nombre d'étapes requises.

Remarque : JavaScript natif (ECMAScript) ou tout autre framework peut accomplir cela. L'utilisation de Vue est à des fins de démonstration.

La barre de progression utilise un balisage de base. Il y a:

  • un conteneur avec des classes calculées en fonction de l'étape courante: progressClasses
  • une piste d'arrière-plan statique: progress__bg
  • une boucle qui parcourt chaque étape et s'applique en stepClassesfonction de l'étape actuelle.

Chaque étape a:

  • a progress__indicatorqui contient une icône de coche qui est visible si l'étape est terminée.
  • a progress__labelqui contient le texte de l'étiquette pour cette étape.
 {{step.label}} Back Next Step: {{currentStep ? currentStep.label : "Start"}} 

Pour plus de simplicité, les progress__actionscommandes qui contrôlent la direction du déplacement sont imbriquées dans la barre de progression elle-même.

Le CSS (SCSS)

C'est là que nous faisons le gros du travail. Les classes définies ici seront appliquées dynamiquement par le JS en fonction de l'étape en cours.

Tout d'abord, sélectionnons quelques couleurs avec lesquelles travailler:

$gray: #E5E5E5; $gray2: #808080; $blue: #2183DD; $green: #009900; $white: #FFFFFF;

Définissez maintenant la .progressclasse: le conteneur qui contient le contenu de la barre de progression ensemble.

.progress { position: absolute; top: 15vh; width: 0%; height: 10px; background-color: $blue; transition: width .2s; }

Notre barre de progression a besoin d'un .progress__bgque les étapes de progression se déroulent comme une piste. Ce sera gris, recouvert par la barre colorée au fur et à mesure qu'il passe à l'étape suivante.

.progress__bg { position: absolute; width: 100vw; height: 10px; background-color: $gray; z-index: -1; }

Chacun .progress__stepcontient le pas rond qui sera mis en surbrillance et se remplir au fur et à mesure que la barre de progression avance.

.progress__step { position: absolute; top: -8px; left: 0; display: flex; flex-direction: column; align-items: center; text-align: center; @for $i from 1 through 5 { &.progress__step--#{$i} { left: calc(#{$i * 20}vw - 9px); } } }

Il contient également le .progress__indicatortexte du rond et de l'étiquette .progress__label. Leurs styles par défaut sont définis en dehors du .progress__step.

.progress__indicator { width: 25px; height: 25px; border: 2px solid $gray2; border-radius: 50%; background-color: $white; margin-bottom: 10px; .fa { display: none; font-size: 16px; color: $white; } } .progress__label { position: absolute; top: 40px; }

Continuons maintenant à nous imbriquer à .progress__stepnouveau et définissons l'étape dans son état actif .

&.progress__step--active { color: $blue; font-weight: 600; }

Ensuite, définissez l'étape dans son état complet . Remarque : les styles par défaut pour .progress__indicatoret .progress__labelsont écrasés lorsqu'ils sont à l'état complet.

&.progress__step--complete { .progress__indicator { background-color: $green; border-color: $blue; color: $white; display: flex; align-items: center; justify-content: center; } .progress__indicator .fa { display: block; } .progress__label { font-weight: 600; color: $green; } }

Le JavaScript

Comme mentionné précédemment, cela différera en fonction de la façon dont vous implémentez la logique d'étape, du contexte plus large dans lequel elle est implémentée, des cadres et des modèles que vous utilisez, etc.

Cet exemple utilise un composant Vue pour démontrer:

  • calcul des classes pour la barre de progression en fonction de l'état actuel.
  • calcul des classes pour chaque étape en fonction de l'état actuel.
var app = new Vue({ el: '#app', data: { currentStep: null, steps: [ {"label": "one"}, {"label": "two"}, {"label": "three"}, {"label": "complete"} ] }, methods: { nextStep(next=true) { const steps = this.steps const currentStep = this.currentStep const currentIndex = steps.indexOf(currentStep) // handle back if (!next) { if (currentStep && currentStep.label === 'complete') { return this.currentStep = steps[steps.length - 1] } if (steps[currentIndex - 1]) { return this.currentStep = steps[currentIndex - 1] } return this.currentStep = { "label": "start" } } // handle next if (this.currentStep && this.currentStep.label === 'complete') { return this.currentStep = { "label": "start" } } if (steps[currentIndex + 1]) { return this.currentStep = steps[currentIndex + 1] } this.currentStep = { "label": "complete" } }, stepClasses(index) { let result = `progress__step progress__step--${index + 1} ` if (this.currentStep && this.currentStep.label === 'complete' || index < this.steps.indexOf(this.currentStep)) { return result += 'progress__step--complete' } if (index === this.steps.indexOf(this.currentStep)) { return result += 'progress__step--active' } return result } }, computed: { progressClasses() { let result = 'progress ' if (this.currentStep && this.currentStep.label === 'complete') { return result += 'progress--complete' } return result += `progress--${this.steps.indexOf(this.currentStep) + 1}` } } })

Conclusion

À la fin de tout cela, vous avez ceci:

Consultez le CodePen pour un exemple en direct.

Si vous trouvez mes articles utiles, envisagez de devenir membre de mon Patreon :)

Ou si vous voulez juste m'acheter du café (j'adore le café):