Simulating Realistic Loading Progress Bars with CSS Animations
The article shows how to create a realistic loading progress bar using only CSS—by styling a container and its ::before pseudo‑element, applying keyframe width animations with ease, cubic‑bezier or the newer linear() timing functions, and toggling between long and short animations via CSS variables for a smooth instant‑complete effect without JavaScript animation code.
During page loading, a progress bar can greatly reduce users' waiting anxiety. Because most of the time the actual loading progress cannot be measured, developers often need to simulate a realistic loading experience using CSS.
Below is a minimal HTML container for the progress bar:
<div class="progress"></div>The visual effect is built with two layers: the outer .progress element and an inner pseudo‑element ::before that represents the current progress.
.progress {
position: relative;
width: 300px;
height: 10px;
margin: 25px 0;
border-radius: 10px;
overflow: hidden;
background-color: #E4CCFF;
}
.progress::before {
position: absolute;
content: '';
width: 0%;
height: 100%;
background: #9747FF;
}Changing the width of ::before animates the progress. A simple keyframe animation from 0% to 100% can be used:
.progress::before {
animation: progress 10s forwards;
}
@keyframes progress {
to { width: 100%; }
}The default timing function ease gives a fast‑then‑slow feel, which is usually more pleasant than a linear motion.
To make the animation feel even more realistic, the cubic‑bezier function can be applied, allowing a faster start and a slower finish.
For finer‑grained control, the newer linear() timing function can define multiple intermediate points, simulating network jitter. Example:
@supports (animation-timing-function: linear(0,1)) {
.progress {
--ease: linear(0,0.25 4.14%,0.53 13.29%,0.61 25.03%,0.75 34.8%,0.88 43.99%,0.93 58.77%,0.98 68.88%,0.99 79.22%,1 88.79%,1 100%);
}
}If linear() is not supported, the fallback is the earlier cubic‑bezier approach.
In many cases the progress bar is only a placeholder; when a critical resource finishes loading, the bar should jump to completion smoothly. This can be achieved by defining two animations with different durations and controlling their play state via CSS variables:
.progress::before {
/* two identical animations with different lengths */
animation: progress 10s var(--ease) forwards,
progress 1s var(--ease) forwards;
animation-play-state: var(--running, running, paused);
}When the resource is ready, a JavaScript handler updates the --running variable to switch the short animation on:
btn.onclick = function() {
document.body.style.setProperty('--running', 'paused, running');
};After the click, the bar finishes within 1 second, providing a smooth “instant‑complete” effect. The final animation can keep the default ease timing for the remaining part.
Overall, the technique combines CSS pseudo‑elements, keyframe animations, timing functions ( ease , cubic‑bezier , linear() ), and CSS variables to create a realistic, controllable loading progress bar without any JavaScript for the animation itself.
Key take‑aways:
Progress bars alleviate user anxiety during loading.
Because true loading progress is often unavailable, simulation is necessary.
The default ease timing gives a fast‑then‑slow feel.
cubic‑bezier can make the initial speed faster.
linear() allows detailed timing curves to mimic network instability.
Active completion can be achieved by switching animation play states.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.