Code Bytes
Animate a progress display without inventing progress
Give a known percentage a small visual entrance, keep its value accessible and distinguish a demonstration from real upload or task progress.
A little progress goes a long way.
A four-second illustration of a progress bar—not a download, upload or network request.
This is the progress bar at rest. Enable JavaScript to start the simulation.
Show a known value honestly
An animation can draw attention to a percentage you already know. It should not pretend that an upload, payment or background job is finishing. The demo here is explicitly a four-second simulation in your browser; it does not measure a network operation.
For a real task, use a native <progress> element and update it from actual task information. Leave its value unset when the amount of work completed is unknown.
A presentation-only example
This version shows a known 75% value immediately and animates only its decorative fill. The text and accessible value do not spend four seconds reporting a false intermediate result.
<p id="completion-label">Checklist completion: 75%</p>
<div class="completion" role="progressbar"
aria-labelledby="completion-label"
aria-valuemin="0" aria-valuemax="100" aria-valuenow="75">
<span class="completion__fill" aria-hidden="true"></span>
</div>
<button type="button" id="replay-completion" hidden>Replay animation</button>
.completion {
overflow: hidden;
block-size: 0.75rem;
background: #e8e7f2;
}
.completion__fill {
display: block;
inline-size: 75%;
block-size: 100%;
background: #3b3a7a;
transform-origin: left center;
}
const fill = document.querySelector('.completion__fill');
const replay = document.querySelector('#replay-completion');
const motion = matchMedia('(prefers-reduced-motion: reduce)');
let animation;
function showProgress() {
animation?.cancel();
if (motion.matches || !fill.animate) return;
animation = fill.animate([
{ transform: 'scaleX(0)' },
{ transform: 'scaleX(1)' },
], { duration: 4000, easing: 'ease-out' });
}
function preferenceChanged() {
if (motion.matches) animation?.cancel();
}
replay.hidden = false;
replay.addEventListener('click', showProgress);
motion.addEventListener('change', preferenceChanged);
showProgress();
function destroyProgress() {
animation?.cancel();
replay.removeEventListener('click', showProgress);
motion.removeEventListener('change', preferenceChanged);
}
Using it on a real page
Load the JavaScript after the markup. The CSS already shows the final value, so no JavaScript or reduced motion leaves a useful static display. Call destroyProgress() when unmounting the component. Swap the colours for your existing design tokens and use the correct transform origin for right-to-left layouts.
If the value changes, update the visible text, aria-valuenow and fill together after validating a finite number in the 0–100 range. Do not communicate success through colour alone, and do not announce every animation frame with a live region.
References: progressbar semantics, Element.animate, and reduced motion.
Original version18 October 2014
Kept here for reference and earlier links. The updated guide above is the recommended starting point; older code may depend on retired services or different software versions.
This is a very easy way of getting a progress bar or similar element to transition from one state/width to another once the website has fully loaded. Useful for enhancing a point, or ability of a company/profile etc if used subtly and effectively.
Demo:
Replay
This works by first of all setting your progress by to 0% via CSS, and then setting up transition rules that any changes will happen over 4 seconds (you can, of course, change this to suit your preference, as well as colours etc.)
The javascript will then set a new width and background colour to the bar which will appear to animate due to the transitions rules mentioned above.
Achievable in simply a few lines of code.
The CSS:
.progress_bar {
height: 15px;
background: orange;
width: 0%;
-moz-transition: all 4s ease;
-moz-transition-delay: 1s;
-webkit-transition: all 4s ease;
-webkit-transition-delay: 1s;
transition: all 4s ease;
transition-delay: 1s;
}
THE HTML:
<div id="progressBar" class="progress_bar"></div>
The Javascript (Vanilla), with a commented line if you want to animate to a percentage output by PHP etc.
// Assign your element ID to a variable.
var progress = document.getElementById("progressBar");
// Pause the animation for 100 so we can animate from 0 to x%
setTimeout(
function(){
progress.style.width = "100%";
// PHP Version:
// progress.style.width = <?php echo round($percentage150,2); ?>+"%";
progress.style.backgroundColor = "green";
}
,100);
The whole code put together, very simple:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple Animated CSS/JS Progress Bar</title>
<link rel="author" href="https://plus.google.com/u/0/116030566292183707588/posts">
<!-- A simple Animated progress by @guwii -->
</head>
<body>
<style>
.progress_bar {
height: 10px;
background: orange;
width: 0%;
-moz-transition: all 4s ease;
-moz-transition-delay: 1s;
-webkit-transition: all 4s ease;
-webkit-transition-delay: 1s;
transition: all 4s ease;
transition-delay: 1s;
}
</style>
<div id="progressBar" class="progress_bar"></div>
<script>
// Assign your element ID to a variable.
var progress = document.getElementById("progressBar");
// Pause the animation for 100 so we can animate from 0 to x%
setTimeout(
function(){
progress.style.width = "100%";
// PHP Version:
// progress.style.width = "<?php echo $progressPercentage; ?>";
progress.style.backgroundColor = "green";
}
,100);
</script>
</body>
</html>
Keep exploring