Cómo crear una barra de progreso dinámica y receptiva con HTML, CSS y JavaScript

Hace un par de años escribí un breve artículo sobre cómo crear una barra de progreso receptiva. Mis técnicas se han desarrollado desde entonces, por lo que es necesario actualizarlas.

El mayor cambio es que los pseudo-elementos (antes, después) ya no son necesarios. Ahora el CSS es más sencillo, el DOM es más fácil de leer y es mucho más dinámico.

Intentemos esto de nuevo.

Nuestro objetivo es crear una barra de progreso receptiva simple y eficaz que haga lo siguiente:

  • Tiene cuatro pasos para completar.
  • Cada paso tiene una default, activey completeestado.
  • Puede progresar paso a paso hasta su finalización.

Consulte CodePen aquí para ver un ejemplo en vivo.

El HTML

Para reducir la redundancia y aumentar la reutilización, rastreamos todo el estado en un componente de Vue. En el DOM, esto genera dinámicamente cualquier número de pasos requeridos.

Nota : JavaScript nativo (ECMAScript) o cualquier otro marco puede lograr esto. El uso de Vue es para fines demostrativos.

La barra de progreso utiliza un marcado básico. Ahi esta:

  • un contenedor con clases calculadas según el paso actual: progressClasses
  • una pista de fondo estática: progress__bg
  • un bucle que recorre cada paso y se aplica stepClassessegún el paso actual.

Cada paso tiene:

  • a progress__indicatorque contiene un icono de verificación que está visible si el paso está completo.
  • a progress__labelque contiene el texto de la etiqueta para ese paso.
 {{step.label}} Back Next Step: {{currentStep ? currentStep.label : "Start"}} 

Para simplificar, los progress__actionsque controlan la dirección de viaje están anidados dentro de la propia barra de progreso.

El CSS (SCSS)

Aquí es donde hacemos el trabajo pesado. Las clases definidas aquí serán aplicadas dinámicamente por JS según el paso actual.

Primero, seleccionemos algunos colores para trabajar:

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

Ahora defina la .progressclase: el contenedor que mantiene juntos los contenidos de la barra de progreso.

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

Nuestra barra de progreso necesita .progress__bgque los pasos de progreso se ejecuten como una pista. Este será gris, cubierto por la barra de color a medida que avanza al siguiente paso.

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

Cada uno .progress__stepcontiene el paso circular que se resaltará y completará a medida que avanza la barra de progreso.

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

También contiene el .progress__indicatortexto redondo y de etiqueta .progress__label. Sus estilos predeterminados se definen fuera de .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; }

Ahora continuemos anidando adentro .progress__stepnuevamente y definamos el paso en su estado activo .

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

A continuación, defina el paso en su estado completo . Nota : los estilos predeterminados para .progress__indicatory .progress__labelse sobrescriben cuando están en estado completo.

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

El JavaScript

Como se mencionó anteriormente, esto diferirá en función de cómo implemente la lógica de pasos, el contexto más amplio en el que se implemente, los marcos y patrones que use, etc.

Este ejemplo usa un componente de Vue para demostrar:

  • cálculo de clases para la barra de progreso basado en el estado actual.
  • cálculo de clases para cada paso basado en el estado actual.
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}` } } })

Conclusión

Al final de todo, tienes esto:

Consulte CodePen para ver un ejemplo en vivo.

Si encuentra útiles mis artículos, por favor considere convertirse en miembro de mi Patreon :)

O si solo quieres comprarme café (me encanta el café):