CSS | Step Progress Transition
by Zoltan Boros
HTML
<div class="steps">
<div class="step" id="step1">
<div class="background completed"></div>
<div class="background pending"></div>
<div class="background upcoming"></div>
Step 1
</div>
<div class="step" id="step2">
<div class="background completed"></div>
<div class="background pending"></div>
<div class="background upcoming"></div>
Step 2
</div>
<div class="step" id="step3">
<div class="background completed"></div>
<div class="background pending"></div>
<div class="background upcoming"></div>
Step 3
</div>
<div class="step" id="step4">
<div class="background completed"></div>
<div class="background pending"></div>
<div class="background upcoming"></div>
Step 4
</div>
<div class="step" id="step5">
<div class="background completed"></div>
<div class="background pending"></div>
<div class="background upcoming"></div>
Step 5
</div>
</div>
<button type="button" id="back">back</button>
<button type="button" id="next">next</button>
CSS
.steps {
margin-bottom: 1rem;
display: flex;
align-items: felx-start;
}
.step {
position: relative;
flex-grow: 1;
overflow: hidden;
margin: 1px;
text-align: center;
}
.step .background {
position: absolute;
width: 100%;
height: 100%;
z-index: -1;
transition: left 0.75s;
}
.step .background.completed {
background-color: #dfd;
}
.step .background.pending {
background-color: #ddf;
}
.step .background.upcoming {
background-color: #fdd;
}
.step.completed .background.completed {
left: 0;
}
.step.completed .background.pending {
left: 100%;
}
.step.completed .background.upcoming {
left: 200%;
}
.step.pending .background.completed {
left: -100;
}
.step.pending .background.pending {
left: 0;
}
.step.pending .background.upcoming {
left: 100%;
}
.step.upcoming .background.completed {
left: -200%;
}
.step.upcoming .background.pending {
left: -100%;
}
.step.upcoming .background.upcoming {
left: 0;
}
JavaScript
const statusClasses = [ 'completed', 'pending', 'upcoming' ];
const steps = [];
for (var i = 1; i <= 5; i++) {
steps.push(document.getElementById(`step${i}`));
}
var currentStepIndex = 0;
const getStatusIndex = (i) => {
return i < currentStepIndex
? 0
: i === currentStepIndex
? 1
: 2;
};
const updateUi = () => {
steps.forEach((step, i) => {
const statusClass = statusClasses[getStatusIndex(i)];
step.className = `step ${statusClass}`;
});
};
const next = () => {
if (currentStepIndex + 1 < steps.length) {
currentStepIndex++;
updateUi();
}
};
const back = () => {
if (currentStepIndex > 0) {
currentStepIndex--;
updateUi();
}
};
document.getElementById('back').addEventListener('click', back);
document.getElementById('next').addEventListener('click', next);
updateUi();