22 CSS Progress Bars16 / 22
Gradient Pulse Progress Bar
The onboarding bar that looks alive: a violet-to-cyan fill with a highlight sheen travelling across it and a glow that breathes on a 3s cycle. Two ambient animations, both compositor-friendly, both switched off under reduced motion.
Published Updated
The code
<div class="pb-16">
<input class="pb-16__sr" type="checkbox" id="pb-16-light">
<label class="pb-16__theme" for="pb-16-light" title="Switch light or dark theme">
<svg class="pb-16__sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.4" stroke="currentColor" stroke-width="1.7"/><path d="M12 2.6v2.3M12 19.1v2.3M2.6 12h2.3M19.1 12h2.3M5.3 5.3l1.7 1.7M17 17l1.7 1.7M18.7 5.3L17 7M7 17l-1.7 1.7" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
<svg class="pb-16__moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20.5 14.4A8.4 8.4 0 0 1 9.6 3.5 8.6 8.6 0 1 0 20.5 14.4Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>
<span class="pb-16__vh">Switch light or dark theme</span>
</label>
<div class="pb-16__stage">
<div class="pb-16__card">
<header class="pb-16__head">
<p class="pb-16__eyebrow"><span class="pb-16__badge">Onboarding</span><span class="pb-16__mono">3 of 4 tasks</span></p>
<h2 class="pb-16__title">You are almost set up</h2>
<p class="pb-16__lead">Finish the last step and your workspace goes live for the whole team.</p>
</header>
<div class="pb-16__hero" role="progressbar" aria-valuenow="78" aria-valuemin="0" aria-valuemax="100" aria-valuetext="78 percent of setup complete" aria-label="Workspace setup" style="--value:78">
<span class="pb-16__heroFill"></span>
<span class="pb-16__heroPct pb-16__mono">78%</span>
</div>
<ul class="pb-16__rows">
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Connect repository</span><span class="pb-16__rowVal pb-16__mono">100%</span></span>
<span class="pb-16__bar pb-16__bar--done" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Connect repository, complete" aria-label="Connect repository" style="--value:100"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Invite teammates</span><span class="pb-16__rowVal pb-16__mono">100%</span></span>
<span class="pb-16__bar pb-16__bar--done" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Invite teammates, complete" aria-label="Invite teammates" style="--value:100"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Import design tokens</span><span class="pb-16__rowVal pb-16__mono">64%</span></span>
<span class="pb-16__bar" role="progressbar" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Import design tokens, 64 percent" aria-label="Import design tokens" style="--value:64"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Set a deploy target</span><span class="pb-16__rowVal pb-16__mono">0%</span></span>
<span class="pb-16__bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Set a deploy target, not started" aria-label="Set a deploy target" style="--value:0"><span class="pb-16__fill"></span></span>
</li>
</ul>
<p class="pb-16__note pb-16__mono">sheen: background-position · glow: box-shadow · no JavaScript</p>
</div>
</div>
</div><div class="pb-16">
<input class="pb-16__sr" type="checkbox" id="pb-16-light">
<label class="pb-16__theme" for="pb-16-light" title="Switch light or dark theme">
<svg class="pb-16__sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.4" stroke="currentColor" stroke-width="1.7"/><path d="M12 2.6v2.3M12 19.1v2.3M2.6 12h2.3M19.1 12h2.3M5.3 5.3l1.7 1.7M17 17l1.7 1.7M18.7 5.3L17 7M7 17l-1.7 1.7" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
<svg class="pb-16__moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20.5 14.4A8.4 8.4 0 0 1 9.6 3.5 8.6 8.6 0 1 0 20.5 14.4Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>
<span class="pb-16__vh">Switch light or dark theme</span>
</label>
<div class="pb-16__stage">
<div class="pb-16__card">
<header class="pb-16__head">
<p class="pb-16__eyebrow"><span class="pb-16__badge">Onboarding</span><span class="pb-16__mono">3 of 4 tasks</span></p>
<h2 class="pb-16__title">You are almost set up</h2>
<p class="pb-16__lead">Finish the last step and your workspace goes live for the whole team.</p>
</header>
<div class="pb-16__hero" role="progressbar" aria-valuenow="78" aria-valuemin="0" aria-valuemax="100" aria-valuetext="78 percent of setup complete" aria-label="Workspace setup" style="--value:78">
<span class="pb-16__heroFill"></span>
<span class="pb-16__heroPct pb-16__mono">78%</span>
</div>
<ul class="pb-16__rows">
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Connect repository</span><span class="pb-16__rowVal pb-16__mono">100%</span></span>
<span class="pb-16__bar pb-16__bar--done" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Connect repository, complete" aria-label="Connect repository" style="--value:100"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Invite teammates</span><span class="pb-16__rowVal pb-16__mono">100%</span></span>
<span class="pb-16__bar pb-16__bar--done" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Invite teammates, complete" aria-label="Invite teammates" style="--value:100"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Import design tokens</span><span class="pb-16__rowVal pb-16__mono">64%</span></span>
<span class="pb-16__bar" role="progressbar" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Import design tokens, 64 percent" aria-label="Import design tokens" style="--value:64"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Set a deploy target</span><span class="pb-16__rowVal pb-16__mono">0%</span></span>
<span class="pb-16__bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Set a deploy target, not started" aria-label="Set a deploy target" style="--value:0"><span class="pb-16__fill"></span></span>
</li>
</ul>
<p class="pb-16__note pb-16__mono">sheen: background-position · glow: box-shadow · no JavaScript</p>
</div>
</div>
</div>.pb-16 {
--bgSolid: #070610;
--card: #0d0b1c;
--ink: #f2f0ff;
--muted: rgba(242,240,255,.62);
--line: rgba(242,240,255,.12);
--track: rgba(242,240,255,.08);
--a: #8b5cf6;
--b: #22d3ee;
--accent: #a78bfa;
--sans: system-ui,-apple-system,"Segoe UI",sans-serif;
--mono: ui-monospace,"JetBrains Mono","Geist Mono",SFMono-Regular,Menlo,monospace;
inline-size: 100%;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--bgSolid);
color: var(--ink);
font-family: var(--sans);
-webkit-font-smoothing: antialiased;
}
@supports (color: oklch(70% .2 290)) {
.pb-16 {
--a: oklch(66% .21 293);
--b: oklch(82% .13 199);
--accent: oklch(76% .16 295);
}
}
.pb-16 *,
.pb-16 *::before,
.pb-16 *::after {
box-sizing: border-box;
}
.pb-16__sr {
position: absolute;
opacity: 0;
pointer-events: none;
}
.pb-16__vh {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.pb-16__stage {
display: grid;
place-items: center;
min-block-size: 100vh;
padding: clamp(1.1rem,4vw,3.5rem);
background: radial-gradient(80% 55% at 15% 0%,color-mix(in srgb,var(--a) 26%,transparent),transparent 58%), radial-gradient(70% 55% at 95% 100%,color-mix(in srgb,var(--b) 20%,transparent),transparent 60%);
}
.pb-16__theme {
position: absolute;
inset-block-start: clamp(.9rem,2.4vw,1.6rem);
inset-inline-end: clamp(.9rem,2.4vw,1.6rem);
z-index: 5;
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
cursor: pointer;
border-radius: 99px;
border: 1px solid var(--line);
color: var(--ink);
background: rgba(255,255,255,.06);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
transition: background .2s,transform .2s;
}
.pb-16__theme:hover {
transform: translateY(-1px);
background: rgba(255,255,255,.12);
}
.pb-16__sr:focus-visible + .pb-16__theme {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.pb-16__theme svg {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.pb-16__sun {
display: none;
}
.pb-16__moon {
display: block;
}
.pb-16__card {
inline-size: min(40rem,100%);
display: grid;
gap: clamp(1rem,2.4vw,1.5rem);
padding: clamp(1.4rem,3.4vw,2.3rem);
border-radius: 1.6rem;
border: 1px solid var(--line);
background: color-mix(in srgb,var(--card) 90%,transparent);
-webkit-backdrop-filter: blur(16px);
backdrop-filter: blur(16px);
box-shadow: 0 1px 0 rgba(255,255,255,.06) inset,0 36px 90px -46px rgba(0,0,0,.95);
}
.pb-16__head {
display: grid;
gap: .45rem;
}
.pb-16__eyebrow {
margin: 0;
display: flex;
flex-wrap: wrap;
gap: .55rem;
align-items: center;
}
.pb-16__badge {
font-family: var(--mono);
font-size: .64rem;
letter-spacing: .12em;
text-transform: uppercase;
padding: .26rem .5rem;
border-radius: .4rem;
color: var(--accent);
background: color-mix(in srgb,var(--a) 20%,transparent);
border: 1px solid color-mix(in srgb,var(--a) 36%,transparent);
}
.pb-16__mono {
font-family: var(--mono);
font-size: .72rem;
color: var(--muted);
font-variant-numeric: tabular-nums;
}
.pb-16__title {
margin: 0;
font-size: clamp(1.45rem,3.5vw,2.1rem);
line-height: 1.12;
letter-spacing: -.024em;
font-weight: 650;
}
.pb-16__lead {
margin: 0;
max-inline-size: 46ch;
font-size: clamp(.9rem,1.5vw,1rem);
line-height: 1.62;
color: var(--muted);
text-wrap: pretty;
}
.pb-16__hero {
position: relative;
inline-size: 100%;
block-size: 1.15rem;
border-radius: 99px;
overflow: hidden;
background: var(--track);
border: 1px solid var(--line);
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset;
display: grid;
align-items: center;
}
.pb-16__heroFill,
.pb-16__fill {
position: absolute;
inset-block: 0;
inset-inline-start: 0;
inline-size: calc(var(--value,0) * 1%);
border-radius: 99px;
background-color: var(--a);
background-image: linear-gradient(90deg,var(--a) 0%,var(--b) 45%,rgba(255,255,255,.55) 50%,var(--b) 55%,var(--a) 100%);
background-size: 280% 100%;
animation: pb-16-sheen 2.6s cubic-bezier(.4,0,.2,1) infinite;
transition: inline-size .45s cubic-bezier(.4,0,.2,1);
}
@keyframes pb-16-sheen {
from {
background-position: 120% 0;
}
to {
background-position: -60% 0;
}
}
.pb-16__hero {
animation: pb-16-breathe 3s ease-in-out infinite;
}
@keyframes pb-16-breathe {
0%,
100% {
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset,0 0 0 0 color-mix(in srgb,var(--accent) 30%,transparent);
}
50% {
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset,0 0 20px 2px color-mix(in srgb,var(--accent) 45%,transparent);
}
}
.pb-16__heroPct {
position: relative;
z-index: 1;
justify-self: end;
margin-inline-end: .6rem;
font-size: .68rem;
font-weight: 700;
color: #0b0620;
text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
.pb-16__rows {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: .85rem;
}
.pb-16__row {
display: grid;
gap: .35rem;
}
.pb-16__rowHead {
display: flex;
justify-content: space-between;
gap: .8rem;
align-items: baseline;
}
.pb-16__rowName {
font-size: .88rem;
font-weight: 550;
}
.pb-16__rowVal {
color: var(--ink);
font-weight: 600;
}
.pb-16__bar {
position: relative;
display: block;
inline-size: 100%;
block-size: .5rem;
border-radius: 99px;
overflow: hidden;
background: var(--track);
border: 1px solid var(--line);
}
.pb-16__row:nth-child(2) .pb-16__fill {
animation-delay: -.4s;
}
.pb-16__row:nth-child(3) .pb-16__fill {
animation-delay: -.8s;
}
.pb-16__row:nth-child(4) .pb-16__fill {
animation-delay: -1.2s;
}
.pb-16__bar--done .pb-16__fill {
animation-play-state: paused;
background-image: linear-gradient(90deg,var(--a),var(--b));
}
.pb-16__note {
margin: 0;
opacity: .7;
}
.pb-16[data-theme="light"],
.pb-16:has(#pb-16-light:checked) {
--bgSolid: #f7f6ff;
--card: #ffffff;
--ink: #140c28;
--muted: rgba(20,12,40,.62);
--line: rgba(20,12,40,.1);
--track: rgba(20,12,40,.08);
--a: #7c3aed;
--b: #0891b2;
--accent: #7c3aed;
}
.pb-16:has(#pb-16-light:checked) .pb-16__theme {
background: rgba(20,12,40,.05);
}
.pb-16:has(#pb-16-light:checked) .pb-16__sun {
display: block;
}
.pb-16:has(#pb-16-light:checked) .pb-16__moon {
display: none;
}
.pb-16:has(#pb-16-light:checked) .pb-16__heroPct {
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
@media (prefers-color-scheme: light) {
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) {
--bgSolid: #f7f6ff;
--card: #ffffff;
--ink: #140c28;
--muted: rgba(20,12,40,.62);
--line: rgba(20,12,40,.1);
--track: rgba(20,12,40,.08);
--a: #7c3aed;
--b: #0891b2;
--accent: #7c3aed;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__theme {
background: rgba(20,12,40,.05);
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__sun {
display: block;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__moon {
display: none;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__heroPct {
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) {
--bgSolid: #070610;
--card: #0d0b1c;
--ink: #f2f0ff;
--muted: rgba(242,240,255,.62);
--line: rgba(242,240,255,.12);
--track: rgba(242,240,255,.08);
--a: #8b5cf6;
--b: #22d3ee;
--accent: #a78bfa;
}
@supports (color: oklch(70% .2 290)) {
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) {
--a: oklch(66% .21 293);
--b: oklch(82% .13 199);
--accent: oklch(76% .16 295);
}
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__theme {
background: rgba(255,255,255,.06);
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__sun {
display: none;
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__moon {
display: block;
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__heroPct {
color: #0b0620;
text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
}
@media (prefers-reduced-motion: reduce) {
.pb-16 *,
.pb-16 *::before,
.pb-16 *::after {
animation: none !important;
transition: none !important;
}
.pb-16__heroFill,
.pb-16__fill {
background-image: linear-gradient(90deg,var(--a),var(--b));
background-size: 100% 100%;
}
}
@media (forced-colors: active) {
.pb-16__card,
.pb-16__hero,
.pb-16__bar,
.pb-16__theme {
border-color: CanvasText;
box-shadow: none;
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
.pb-16__heroFill,
.pb-16__fill {
background: Highlight;
}
.pb-16__heroPct {
color: CanvasText;
text-shadow: none;
}
}.pb-16 {
--bgSolid: #070610;
--card: #0d0b1c;
--ink: #f2f0ff;
--muted: rgba(242,240,255,.62);
--line: rgba(242,240,255,.12);
--track: rgba(242,240,255,.08);
--a: #8b5cf6;
--b: #22d3ee;
--accent: #a78bfa;
--sans: system-ui,-apple-system,"Segoe UI",sans-serif;
--mono: ui-monospace,"JetBrains Mono","Geist Mono",SFMono-Regular,Menlo,monospace;
inline-size: 100%;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--bgSolid);
color: var(--ink);
font-family: var(--sans);
-webkit-font-smoothing: antialiased;
}
@supports (color: oklch(70% .2 290)) {
.pb-16 {
--a: oklch(66% .21 293);
--b: oklch(82% .13 199);
--accent: oklch(76% .16 295);
}
}
.pb-16 *,
.pb-16 *::before,
.pb-16 *::after {
box-sizing: border-box;
}
.pb-16__sr {
position: absolute;
opacity: 0;
pointer-events: none;
}
.pb-16__vh {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.pb-16__stage {
display: grid;
place-items: center;
min-block-size: 100vh;
padding: clamp(1.1rem,4vw,3.5rem);
background: radial-gradient(80% 55% at 15% 0%,color-mix(in srgb,var(--a) 26%,transparent),transparent 58%), radial-gradient(70% 55% at 95% 100%,color-mix(in srgb,var(--b) 20%,transparent),transparent 60%);
}
.pb-16__theme {
position: absolute;
inset-block-start: clamp(.9rem,2.4vw,1.6rem);
inset-inline-end: clamp(.9rem,2.4vw,1.6rem);
z-index: 5;
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
cursor: pointer;
border-radius: 99px;
border: 1px solid var(--line);
color: var(--ink);
background: rgba(255,255,255,.06);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
transition: background .2s,transform .2s;
}
.pb-16__theme:hover {
transform: translateY(-1px);
background: rgba(255,255,255,.12);
}
.pb-16__sr:focus-visible + .pb-16__theme {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.pb-16__theme svg {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.pb-16__sun {
display: none;
}
.pb-16__moon {
display: block;
}
.pb-16__card {
inline-size: min(40rem,100%);
display: grid;
gap: clamp(1rem,2.4vw,1.5rem);
padding: clamp(1.4rem,3.4vw,2.3rem);
border-radius: 1.6rem;
border: 1px solid var(--line);
background: color-mix(in srgb,var(--card) 90%,transparent);
-webkit-backdrop-filter: blur(16px);
backdrop-filter: blur(16px);
box-shadow: 0 1px 0 rgba(255,255,255,.06) inset,0 36px 90px -46px rgba(0,0,0,.95);
}
.pb-16__head {
display: grid;
gap: .45rem;
}
.pb-16__eyebrow {
margin: 0;
display: flex;
flex-wrap: wrap;
gap: .55rem;
align-items: center;
}
.pb-16__badge {
font-family: var(--mono);
font-size: .64rem;
letter-spacing: .12em;
text-transform: uppercase;
padding: .26rem .5rem;
border-radius: .4rem;
color: var(--accent);
background: color-mix(in srgb,var(--a) 20%,transparent);
border: 1px solid color-mix(in srgb,var(--a) 36%,transparent);
}
.pb-16__mono {
font-family: var(--mono);
font-size: .72rem;
color: var(--muted);
font-variant-numeric: tabular-nums;
}
.pb-16__title {
margin: 0;
font-size: clamp(1.45rem,3.5vw,2.1rem);
line-height: 1.12;
letter-spacing: -.024em;
font-weight: 650;
}
.pb-16__lead {
margin: 0;
max-inline-size: 46ch;
font-size: clamp(.9rem,1.5vw,1rem);
line-height: 1.62;
color: var(--muted);
text-wrap: pretty;
}
.pb-16__hero {
position: relative;
inline-size: 100%;
block-size: 1.15rem;
border-radius: 99px;
overflow: hidden;
background: var(--track);
border: 1px solid var(--line);
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset;
display: grid;
align-items: center;
}
.pb-16__heroFill,
.pb-16__fill {
position: absolute;
inset-block: 0;
inset-inline-start: 0;
inline-size: calc(var(--value,0) * 1%);
border-radius: 99px;
background-color: var(--a);
background-image: linear-gradient(90deg,var(--a) 0%,var(--b) 45%,rgba(255,255,255,.55) 50%,var(--b) 55%,var(--a) 100%);
background-size: 280% 100%;
animation: pb-16-sheen 2.6s cubic-bezier(.4,0,.2,1) infinite;
transition: inline-size .45s cubic-bezier(.4,0,.2,1);
}
@keyframes pb-16-sheen {
from {
background-position: 120% 0;
}
to {
background-position: -60% 0;
}
}
.pb-16__hero {
animation: pb-16-breathe 3s ease-in-out infinite;
}
@keyframes pb-16-breathe {
0%,
100% {
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset,0 0 0 0 color-mix(in srgb,var(--accent) 30%,transparent);
}
50% {
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset,0 0 20px 2px color-mix(in srgb,var(--accent) 45%,transparent);
}
}
.pb-16__heroPct {
position: relative;
z-index: 1;
justify-self: end;
margin-inline-end: .6rem;
font-size: .68rem;
font-weight: 700;
color: #0b0620;
text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
.pb-16__rows {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: .85rem;
}
.pb-16__row {
display: grid;
gap: .35rem;
}
.pb-16__rowHead {
display: flex;
justify-content: space-between;
gap: .8rem;
align-items: baseline;
}
.pb-16__rowName {
font-size: .88rem;
font-weight: 550;
}
.pb-16__rowVal {
color: var(--ink);
font-weight: 600;
}
.pb-16__bar {
position: relative;
display: block;
inline-size: 100%;
block-size: .5rem;
border-radius: 99px;
overflow: hidden;
background: var(--track);
border: 1px solid var(--line);
}
.pb-16__row:nth-child(2) .pb-16__fill {
animation-delay: -.4s;
}
.pb-16__row:nth-child(3) .pb-16__fill {
animation-delay: -.8s;
}
.pb-16__row:nth-child(4) .pb-16__fill {
animation-delay: -1.2s;
}
.pb-16__bar--done .pb-16__fill {
animation-play-state: paused;
background-image: linear-gradient(90deg,var(--a),var(--b));
}
.pb-16__note {
margin: 0;
opacity: .7;
}
.pb-16[data-theme="light"],
.pb-16:has(#pb-16-light:checked) {
--bgSolid: #f7f6ff;
--card: #ffffff;
--ink: #140c28;
--muted: rgba(20,12,40,.62);
--line: rgba(20,12,40,.1);
--track: rgba(20,12,40,.08);
--a: #7c3aed;
--b: #0891b2;
--accent: #7c3aed;
}
.pb-16:has(#pb-16-light:checked) .pb-16__theme {
background: rgba(20,12,40,.05);
}
.pb-16:has(#pb-16-light:checked) .pb-16__sun {
display: block;
}
.pb-16:has(#pb-16-light:checked) .pb-16__moon {
display: none;
}
.pb-16:has(#pb-16-light:checked) .pb-16__heroPct {
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
@media (prefers-color-scheme: light) {
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) {
--bgSolid: #f7f6ff;
--card: #ffffff;
--ink: #140c28;
--muted: rgba(20,12,40,.62);
--line: rgba(20,12,40,.1);
--track: rgba(20,12,40,.08);
--a: #7c3aed;
--b: #0891b2;
--accent: #7c3aed;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__theme {
background: rgba(20,12,40,.05);
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__sun {
display: block;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__moon {
display: none;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__heroPct {
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) {
--bgSolid: #070610;
--card: #0d0b1c;
--ink: #f2f0ff;
--muted: rgba(242,240,255,.62);
--line: rgba(242,240,255,.12);
--track: rgba(242,240,255,.08);
--a: #8b5cf6;
--b: #22d3ee;
--accent: #a78bfa;
}
@supports (color: oklch(70% .2 290)) {
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) {
--a: oklch(66% .21 293);
--b: oklch(82% .13 199);
--accent: oklch(76% .16 295);
}
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__theme {
background: rgba(255,255,255,.06);
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__sun {
display: none;
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__moon {
display: block;
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__heroPct {
color: #0b0620;
text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
}
@media (prefers-reduced-motion: reduce) {
.pb-16 *,
.pb-16 *::before,
.pb-16 *::after {
animation: none !important;
transition: none !important;
}
.pb-16__heroFill,
.pb-16__fill {
background-image: linear-gradient(90deg,var(--a),var(--b));
background-size: 100% 100%;
}
}
@media (forced-colors: active) {
.pb-16__card,
.pb-16__hero,
.pb-16__bar,
.pb-16__theme {
border-color: CanvasText;
box-shadow: none;
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
.pb-16__heroFill,
.pb-16__fill {
background: Highlight;
}
.pb-16__heroPct {
color: CanvasText;
text-shadow: none;
}
}Here's a working CSS Progress Bar from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Gradient Pulse Progress Bar
Source: https://codefronts.com/components/css-progress-bars/gradient-pulse/
The onboarding bar that looks alive: a violet-to-cyan fill with a highlight sheen travelling across it and a glow that breathes on a 3s cycle. Two ambient animations, both compositor-friendly, both switched off under reduced motion.
## HTML
```html
<div class="pb-16">
<input class="pb-16__sr" type="checkbox" id="pb-16-light">
<label class="pb-16__theme" for="pb-16-light" title="Switch light or dark theme">
<svg class="pb-16__sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.4" stroke="currentColor" stroke-width="1.7"/><path d="M12 2.6v2.3M12 19.1v2.3M2.6 12h2.3M19.1 12h2.3M5.3 5.3l1.7 1.7M17 17l1.7 1.7M18.7 5.3L17 7M7 17l-1.7 1.7" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
<svg class="pb-16__moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20.5 14.4A8.4 8.4 0 0 1 9.6 3.5 8.6 8.6 0 1 0 20.5 14.4Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>
<span class="pb-16__vh">Switch light or dark theme</span>
</label>
<div class="pb-16__stage">
<div class="pb-16__card">
<header class="pb-16__head">
<p class="pb-16__eyebrow"><span class="pb-16__badge">Onboarding</span><span class="pb-16__mono">3 of 4 tasks</span></p>
<h2 class="pb-16__title">You are almost set up</h2>
<p class="pb-16__lead">Finish the last step and your workspace goes live for the whole team.</p>
</header>
<div class="pb-16__hero" role="progressbar" aria-valuenow="78" aria-valuemin="0" aria-valuemax="100" aria-valuetext="78 percent of setup complete" aria-label="Workspace setup" style="--value:78">
<span class="pb-16__heroFill"></span>
<span class="pb-16__heroPct pb-16__mono">78%</span>
</div>
<ul class="pb-16__rows">
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Connect repository</span><span class="pb-16__rowVal pb-16__mono">100%</span></span>
<span class="pb-16__bar pb-16__bar--done" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Connect repository, complete" aria-label="Connect repository" style="--value:100"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Invite teammates</span><span class="pb-16__rowVal pb-16__mono">100%</span></span>
<span class="pb-16__bar pb-16__bar--done" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Invite teammates, complete" aria-label="Invite teammates" style="--value:100"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Import design tokens</span><span class="pb-16__rowVal pb-16__mono">64%</span></span>
<span class="pb-16__bar" role="progressbar" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Import design tokens, 64 percent" aria-label="Import design tokens" style="--value:64"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Set a deploy target</span><span class="pb-16__rowVal pb-16__mono">0%</span></span>
<span class="pb-16__bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Set a deploy target, not started" aria-label="Set a deploy target" style="--value:0"><span class="pb-16__fill"></span></span>
</li>
</ul>
<p class="pb-16__note pb-16__mono">sheen: background-position · glow: box-shadow · no JavaScript</p>
</div>
</div>
</div>
```
## CSS
```css
.pb-16 {
--bgSolid: #070610;
--card: #0d0b1c;
--ink: #f2f0ff;
--muted: rgba(242,240,255,.62);
--line: rgba(242,240,255,.12);
--track: rgba(242,240,255,.08);
--a: #8b5cf6;
--b: #22d3ee;
--accent: #a78bfa;
--sans: system-ui,-apple-system,"Segoe UI",sans-serif;
--mono: ui-monospace,"JetBrains Mono","Geist Mono",SFMono-Regular,Menlo,monospace;
inline-size: 100%;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--bgSolid);
color: var(--ink);
font-family: var(--sans);
-webkit-font-smoothing: antialiased;
}
@supports (color: oklch(70% .2 290)) {
.pb-16 {
--a: oklch(66% .21 293);
--b: oklch(82% .13 199);
--accent: oklch(76% .16 295);
}
}
.pb-16 *,
.pb-16 *::before,
.pb-16 *::after {
box-sizing: border-box;
}
.pb-16__sr {
position: absolute;
opacity: 0;
pointer-events: none;
}
.pb-16__vh {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.pb-16__stage {
display: grid;
place-items: center;
min-block-size: 100vh;
padding: clamp(1.1rem,4vw,3.5rem);
background: radial-gradient(80% 55% at 15% 0%,color-mix(in srgb,var(--a) 26%,transparent),transparent 58%), radial-gradient(70% 55% at 95% 100%,color-mix(in srgb,var(--b) 20%,transparent),transparent 60%);
}
.pb-16__theme {
position: absolute;
inset-block-start: clamp(.9rem,2.4vw,1.6rem);
inset-inline-end: clamp(.9rem,2.4vw,1.6rem);
z-index: 5;
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
cursor: pointer;
border-radius: 99px;
border: 1px solid var(--line);
color: var(--ink);
background: rgba(255,255,255,.06);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
transition: background .2s,transform .2s;
}
.pb-16__theme:hover {
transform: translateY(-1px);
background: rgba(255,255,255,.12);
}
.pb-16__sr:focus-visible + .pb-16__theme {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.pb-16__theme svg {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.pb-16__sun {
display: none;
}
.pb-16__moon {
display: block;
}
.pb-16__card {
inline-size: min(40rem,100%);
display: grid;
gap: clamp(1rem,2.4vw,1.5rem);
padding: clamp(1.4rem,3.4vw,2.3rem);
border-radius: 1.6rem;
border: 1px solid var(--line);
background: color-mix(in srgb,var(--card) 90%,transparent);
-webkit-backdrop-filter: blur(16px);
backdrop-filter: blur(16px);
box-shadow: 0 1px 0 rgba(255,255,255,.06) inset,0 36px 90px -46px rgba(0,0,0,.95);
}
.pb-16__head {
display: grid;
gap: .45rem;
}
.pb-16__eyebrow {
margin: 0;
display: flex;
flex-wrap: wrap;
gap: .55rem;
align-items: center;
}
.pb-16__badge {
font-family: var(--mono);
font-size: .64rem;
letter-spacing: .12em;
text-transform: uppercase;
padding: .26rem .5rem;
border-radius: .4rem;
color: var(--accent);
background: color-mix(in srgb,var(--a) 20%,transparent);
border: 1px solid color-mix(in srgb,var(--a) 36%,transparent);
}
.pb-16__mono {
font-family: var(--mono);
font-size: .72rem;
color: var(--muted);
font-variant-numeric: tabular-nums;
}
.pb-16__title {
margin: 0;
font-size: clamp(1.45rem,3.5vw,2.1rem);
line-height: 1.12;
letter-spacing: -.024em;
font-weight: 650;
}
.pb-16__lead {
margin: 0;
max-inline-size: 46ch;
font-size: clamp(.9rem,1.5vw,1rem);
line-height: 1.62;
color: var(--muted);
text-wrap: pretty;
}
.pb-16__hero {
position: relative;
inline-size: 100%;
block-size: 1.15rem;
border-radius: 99px;
overflow: hidden;
background: var(--track);
border: 1px solid var(--line);
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset;
display: grid;
align-items: center;
}
.pb-16__heroFill,
.pb-16__fill {
position: absolute;
inset-block: 0;
inset-inline-start: 0;
inline-size: calc(var(--value,0) * 1%);
border-radius: 99px;
background-color: var(--a);
background-image: linear-gradient(90deg,var(--a) 0%,var(--b) 45%,rgba(255,255,255,.55) 50%,var(--b) 55%,var(--a) 100%);
background-size: 280% 100%;
animation: pb-16-sheen 2.6s cubic-bezier(.4,0,.2,1) infinite;
transition: inline-size .45s cubic-bezier(.4,0,.2,1);
}
@keyframes pb-16-sheen {
from {
background-position: 120% 0;
}
to {
background-position: -60% 0;
}
}
.pb-16__hero {
animation: pb-16-breathe 3s ease-in-out infinite;
}
@keyframes pb-16-breathe {
0%,
100% {
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset,0 0 0 0 color-mix(in srgb,var(--accent) 30%,transparent);
}
50% {
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset,0 0 20px 2px color-mix(in srgb,var(--accent) 45%,transparent);
}
}
.pb-16__heroPct {
position: relative;
z-index: 1;
justify-self: end;
margin-inline-end: .6rem;
font-size: .68rem;
font-weight: 700;
color: #0b0620;
text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
.pb-16__rows {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: .85rem;
}
.pb-16__row {
display: grid;
gap: .35rem;
}
.pb-16__rowHead {
display: flex;
justify-content: space-between;
gap: .8rem;
align-items: baseline;
}
.pb-16__rowName {
font-size: .88rem;
font-weight: 550;
}
.pb-16__rowVal {
color: var(--ink);
font-weight: 600;
}
.pb-16__bar {
position: relative;
display: block;
inline-size: 100%;
block-size: .5rem;
border-radius: 99px;
overflow: hidden;
background: var(--track);
border: 1px solid var(--line);
}
.pb-16__row:nth-child(2) .pb-16__fill {
animation-delay: -.4s;
}
.pb-16__row:nth-child(3) .pb-16__fill {
animation-delay: -.8s;
}
.pb-16__row:nth-child(4) .pb-16__fill {
animation-delay: -1.2s;
}
.pb-16__bar--done .pb-16__fill {
animation-play-state: paused;
background-image: linear-gradient(90deg,var(--a),var(--b));
}
.pb-16__note {
margin: 0;
opacity: .7;
}
.pb-16[data-theme="light"],
.pb-16:has(#pb-16-light:checked) {
--bgSolid: #f7f6ff;
--card: #ffffff;
--ink: #140c28;
--muted: rgba(20,12,40,.62);
--line: rgba(20,12,40,.1);
--track: rgba(20,12,40,.08);
--a: #7c3aed;
--b: #0891b2;
--accent: #7c3aed;
}
.pb-16:has(#pb-16-light:checked) .pb-16__theme {
background: rgba(20,12,40,.05);
}
.pb-16:has(#pb-16-light:checked) .pb-16__sun {
display: block;
}
.pb-16:has(#pb-16-light:checked) .pb-16__moon {
display: none;
}
.pb-16:has(#pb-16-light:checked) .pb-16__heroPct {
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
@media (prefers-color-scheme: light) {
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) {
--bgSolid: #f7f6ff;
--card: #ffffff;
--ink: #140c28;
--muted: rgba(20,12,40,.62);
--line: rgba(20,12,40,.1);
--track: rgba(20,12,40,.08);
--a: #7c3aed;
--b: #0891b2;
--accent: #7c3aed;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__theme {
background: rgba(20,12,40,.05);
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__sun {
display: block;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__moon {
display: none;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__heroPct {
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) {
--bgSolid: #070610;
--card: #0d0b1c;
--ink: #f2f0ff;
--muted: rgba(242,240,255,.62);
--line: rgba(242,240,255,.12);
--track: rgba(242,240,255,.08);
--a: #8b5cf6;
--b: #22d3ee;
--accent: #a78bfa;
}
@supports (color: oklch(70% .2 290)) {
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) {
--a: oklch(66% .21 293);
--b: oklch(82% .13 199);
--accent: oklch(76% .16 295);
}
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__theme {
background: rgba(255,255,255,.06);
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__sun {
display: none;
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__moon {
display: block;
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__heroPct {
color: #0b0620;
text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
}
@media (prefers-reduced-motion: reduce) {
.pb-16 *,
.pb-16 *::before,
.pb-16 *::after {
animation: none !important;
transition: none !important;
}
.pb-16__heroFill,
.pb-16__fill {
background-image: linear-gradient(90deg,var(--a),var(--b));
background-size: 100% 100%;
}
}
@media (forced-colors: active) {
.pb-16__card,
.pb-16__hero,
.pb-16__bar,
.pb-16__theme {
border-color: CanvasText;
box-shadow: none;
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
.pb-16__heroFill,
.pb-16__fill {
background: Highlight;
}
.pb-16__heroPct {
color: CanvasText;
text-shadow: none;
}
}
```Here's a working CSS Progress Bar from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Gradient Pulse Progress Bar
Source: https://codefronts.com/components/css-progress-bars/gradient-pulse/
The onboarding bar that looks alive: a violet-to-cyan fill with a highlight sheen travelling across it and a glow that breathes on a 3s cycle. Two ambient animations, both compositor-friendly, both switched off under reduced motion.
## HTML
```html
<div class="pb-16">
<input class="pb-16__sr" type="checkbox" id="pb-16-light">
<label class="pb-16__theme" for="pb-16-light" title="Switch light or dark theme">
<svg class="pb-16__sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.4" stroke="currentColor" stroke-width="1.7"/><path d="M12 2.6v2.3M12 19.1v2.3M2.6 12h2.3M19.1 12h2.3M5.3 5.3l1.7 1.7M17 17l1.7 1.7M18.7 5.3L17 7M7 17l-1.7 1.7" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
<svg class="pb-16__moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20.5 14.4A8.4 8.4 0 0 1 9.6 3.5 8.6 8.6 0 1 0 20.5 14.4Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>
<span class="pb-16__vh">Switch light or dark theme</span>
</label>
<div class="pb-16__stage">
<div class="pb-16__card">
<header class="pb-16__head">
<p class="pb-16__eyebrow"><span class="pb-16__badge">Onboarding</span><span class="pb-16__mono">3 of 4 tasks</span></p>
<h2 class="pb-16__title">You are almost set up</h2>
<p class="pb-16__lead">Finish the last step and your workspace goes live for the whole team.</p>
</header>
<div class="pb-16__hero" role="progressbar" aria-valuenow="78" aria-valuemin="0" aria-valuemax="100" aria-valuetext="78 percent of setup complete" aria-label="Workspace setup" style="--value:78">
<span class="pb-16__heroFill"></span>
<span class="pb-16__heroPct pb-16__mono">78%</span>
</div>
<ul class="pb-16__rows">
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Connect repository</span><span class="pb-16__rowVal pb-16__mono">100%</span></span>
<span class="pb-16__bar pb-16__bar--done" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Connect repository, complete" aria-label="Connect repository" style="--value:100"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Invite teammates</span><span class="pb-16__rowVal pb-16__mono">100%</span></span>
<span class="pb-16__bar pb-16__bar--done" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Invite teammates, complete" aria-label="Invite teammates" style="--value:100"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Import design tokens</span><span class="pb-16__rowVal pb-16__mono">64%</span></span>
<span class="pb-16__bar" role="progressbar" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Import design tokens, 64 percent" aria-label="Import design tokens" style="--value:64"><span class="pb-16__fill"></span></span>
</li>
<li class="pb-16__row">
<span class="pb-16__rowHead"><span class="pb-16__rowName">Set a deploy target</span><span class="pb-16__rowVal pb-16__mono">0%</span></span>
<span class="pb-16__bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-valuetext="Set a deploy target, not started" aria-label="Set a deploy target" style="--value:0"><span class="pb-16__fill"></span></span>
</li>
</ul>
<p class="pb-16__note pb-16__mono">sheen: background-position · glow: box-shadow · no JavaScript</p>
</div>
</div>
</div>
```
## CSS
```css
.pb-16 {
--bgSolid: #070610;
--card: #0d0b1c;
--ink: #f2f0ff;
--muted: rgba(242,240,255,.62);
--line: rgba(242,240,255,.12);
--track: rgba(242,240,255,.08);
--a: #8b5cf6;
--b: #22d3ee;
--accent: #a78bfa;
--sans: system-ui,-apple-system,"Segoe UI",sans-serif;
--mono: ui-monospace,"JetBrains Mono","Geist Mono",SFMono-Regular,Menlo,monospace;
inline-size: 100%;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--bgSolid);
color: var(--ink);
font-family: var(--sans);
-webkit-font-smoothing: antialiased;
}
@supports (color: oklch(70% .2 290)) {
.pb-16 {
--a: oklch(66% .21 293);
--b: oklch(82% .13 199);
--accent: oklch(76% .16 295);
}
}
.pb-16 *,
.pb-16 *::before,
.pb-16 *::after {
box-sizing: border-box;
}
.pb-16__sr {
position: absolute;
opacity: 0;
pointer-events: none;
}
.pb-16__vh {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.pb-16__stage {
display: grid;
place-items: center;
min-block-size: 100vh;
padding: clamp(1.1rem,4vw,3.5rem);
background: radial-gradient(80% 55% at 15% 0%,color-mix(in srgb,var(--a) 26%,transparent),transparent 58%), radial-gradient(70% 55% at 95% 100%,color-mix(in srgb,var(--b) 20%,transparent),transparent 60%);
}
.pb-16__theme {
position: absolute;
inset-block-start: clamp(.9rem,2.4vw,1.6rem);
inset-inline-end: clamp(.9rem,2.4vw,1.6rem);
z-index: 5;
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
cursor: pointer;
border-radius: 99px;
border: 1px solid var(--line);
color: var(--ink);
background: rgba(255,255,255,.06);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
transition: background .2s,transform .2s;
}
.pb-16__theme:hover {
transform: translateY(-1px);
background: rgba(255,255,255,.12);
}
.pb-16__sr:focus-visible + .pb-16__theme {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.pb-16__theme svg {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.pb-16__sun {
display: none;
}
.pb-16__moon {
display: block;
}
.pb-16__card {
inline-size: min(40rem,100%);
display: grid;
gap: clamp(1rem,2.4vw,1.5rem);
padding: clamp(1.4rem,3.4vw,2.3rem);
border-radius: 1.6rem;
border: 1px solid var(--line);
background: color-mix(in srgb,var(--card) 90%,transparent);
-webkit-backdrop-filter: blur(16px);
backdrop-filter: blur(16px);
box-shadow: 0 1px 0 rgba(255,255,255,.06) inset,0 36px 90px -46px rgba(0,0,0,.95);
}
.pb-16__head {
display: grid;
gap: .45rem;
}
.pb-16__eyebrow {
margin: 0;
display: flex;
flex-wrap: wrap;
gap: .55rem;
align-items: center;
}
.pb-16__badge {
font-family: var(--mono);
font-size: .64rem;
letter-spacing: .12em;
text-transform: uppercase;
padding: .26rem .5rem;
border-radius: .4rem;
color: var(--accent);
background: color-mix(in srgb,var(--a) 20%,transparent);
border: 1px solid color-mix(in srgb,var(--a) 36%,transparent);
}
.pb-16__mono {
font-family: var(--mono);
font-size: .72rem;
color: var(--muted);
font-variant-numeric: tabular-nums;
}
.pb-16__title {
margin: 0;
font-size: clamp(1.45rem,3.5vw,2.1rem);
line-height: 1.12;
letter-spacing: -.024em;
font-weight: 650;
}
.pb-16__lead {
margin: 0;
max-inline-size: 46ch;
font-size: clamp(.9rem,1.5vw,1rem);
line-height: 1.62;
color: var(--muted);
text-wrap: pretty;
}
.pb-16__hero {
position: relative;
inline-size: 100%;
block-size: 1.15rem;
border-radius: 99px;
overflow: hidden;
background: var(--track);
border: 1px solid var(--line);
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset;
display: grid;
align-items: center;
}
.pb-16__heroFill,
.pb-16__fill {
position: absolute;
inset-block: 0;
inset-inline-start: 0;
inline-size: calc(var(--value,0) * 1%);
border-radius: 99px;
background-color: var(--a);
background-image: linear-gradient(90deg,var(--a) 0%,var(--b) 45%,rgba(255,255,255,.55) 50%,var(--b) 55%,var(--a) 100%);
background-size: 280% 100%;
animation: pb-16-sheen 2.6s cubic-bezier(.4,0,.2,1) infinite;
transition: inline-size .45s cubic-bezier(.4,0,.2,1);
}
@keyframes pb-16-sheen {
from {
background-position: 120% 0;
}
to {
background-position: -60% 0;
}
}
.pb-16__hero {
animation: pb-16-breathe 3s ease-in-out infinite;
}
@keyframes pb-16-breathe {
0%,
100% {
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset,0 0 0 0 color-mix(in srgb,var(--accent) 30%,transparent);
}
50% {
box-shadow: 0 2px 5px rgba(0,0,0,.4) inset,0 0 20px 2px color-mix(in srgb,var(--accent) 45%,transparent);
}
}
.pb-16__heroPct {
position: relative;
z-index: 1;
justify-self: end;
margin-inline-end: .6rem;
font-size: .68rem;
font-weight: 700;
color: #0b0620;
text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
.pb-16__rows {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: .85rem;
}
.pb-16__row {
display: grid;
gap: .35rem;
}
.pb-16__rowHead {
display: flex;
justify-content: space-between;
gap: .8rem;
align-items: baseline;
}
.pb-16__rowName {
font-size: .88rem;
font-weight: 550;
}
.pb-16__rowVal {
color: var(--ink);
font-weight: 600;
}
.pb-16__bar {
position: relative;
display: block;
inline-size: 100%;
block-size: .5rem;
border-radius: 99px;
overflow: hidden;
background: var(--track);
border: 1px solid var(--line);
}
.pb-16__row:nth-child(2) .pb-16__fill {
animation-delay: -.4s;
}
.pb-16__row:nth-child(3) .pb-16__fill {
animation-delay: -.8s;
}
.pb-16__row:nth-child(4) .pb-16__fill {
animation-delay: -1.2s;
}
.pb-16__bar--done .pb-16__fill {
animation-play-state: paused;
background-image: linear-gradient(90deg,var(--a),var(--b));
}
.pb-16__note {
margin: 0;
opacity: .7;
}
.pb-16[data-theme="light"],
.pb-16:has(#pb-16-light:checked) {
--bgSolid: #f7f6ff;
--card: #ffffff;
--ink: #140c28;
--muted: rgba(20,12,40,.62);
--line: rgba(20,12,40,.1);
--track: rgba(20,12,40,.08);
--a: #7c3aed;
--b: #0891b2;
--accent: #7c3aed;
}
.pb-16:has(#pb-16-light:checked) .pb-16__theme {
background: rgba(20,12,40,.05);
}
.pb-16:has(#pb-16-light:checked) .pb-16__sun {
display: block;
}
.pb-16:has(#pb-16-light:checked) .pb-16__moon {
display: none;
}
.pb-16:has(#pb-16-light:checked) .pb-16__heroPct {
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
@media (prefers-color-scheme: light) {
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) {
--bgSolid: #f7f6ff;
--card: #ffffff;
--ink: #140c28;
--muted: rgba(20,12,40,.62);
--line: rgba(20,12,40,.1);
--track: rgba(20,12,40,.08);
--a: #7c3aed;
--b: #0891b2;
--accent: #7c3aed;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__theme {
background: rgba(20,12,40,.05);
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__sun {
display: block;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__moon {
display: none;
}
.pb-16:not([data-theme="dark"]):not(:has(#pb-16-light:checked)) .pb-16__heroPct {
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) {
--bgSolid: #070610;
--card: #0d0b1c;
--ink: #f2f0ff;
--muted: rgba(242,240,255,.62);
--line: rgba(242,240,255,.12);
--track: rgba(242,240,255,.08);
--a: #8b5cf6;
--b: #22d3ee;
--accent: #a78bfa;
}
@supports (color: oklch(70% .2 290)) {
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) {
--a: oklch(66% .21 293);
--b: oklch(82% .13 199);
--accent: oklch(76% .16 295);
}
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__theme {
background: rgba(255,255,255,.06);
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__sun {
display: none;
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__moon {
display: block;
}
.pb-16:not([data-theme="light"]):has(#pb-16-light:checked) .pb-16__heroPct {
color: #0b0620;
text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
}
@media (prefers-reduced-motion: reduce) {
.pb-16 *,
.pb-16 *::before,
.pb-16 *::after {
animation: none !important;
transition: none !important;
}
.pb-16__heroFill,
.pb-16__fill {
background-image: linear-gradient(90deg,var(--a),var(--b));
background-size: 100% 100%;
}
}
@media (forced-colors: active) {
.pb-16__card,
.pb-16__hero,
.pb-16__bar,
.pb-16__theme {
border-color: CanvasText;
box-shadow: none;
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
.pb-16__heroFill,
.pb-16__fill {
background: Highlight;
}
.pb-16__heroPct {
color: CanvasText;
text-shadow: none;
}
}
```How this works
The sheen is a third colour stop that moves. Make the background wider than the element, then slide it. The gradient's white band crosses the fill on every loop:
.fill{
background-image:linear-gradient(90deg,var(--a) 0%,var(--b) 45%,rgba(255,255,255,.55) 50%,var(--b) 55%,var(--a) 100%);
background-size:280% 100%;
animation:sheen 2.6s cubic-bezier(.4,0,.2,1) infinite;
}
@keyframes sheen{ from{ background-position:120% 0; } to{ background-position:-60% 0; } }Glow needs restraint. box-shadow is a paint-heavy property, so animate it slowly, on one element, with two keyframes — never on a list of ten rows at 60fps:
@keyframes breathe{
0%,100%{ box-shadow:0 0 0 0 color-mix(in oklab,var(--accent) 30%,transparent); }
50% { box-shadow:0 0 18px 2px color-mix(in oklab,var(--accent) 45%,transparent); }
}Stagger, or it looks mechanical. Three bars pulsing in unison read as a loading screen; the same three offset by 400ms read as a live system:
.row:nth-child(2) .fill{ animation-delay:-.4s; }
.row:nth-child(3) .fill{ animation-delay:-.8s; }Interpolate in oklch if you can. A violet-to-cyan gradient in sRGB passes through a grey-blue dip; the same two ends in oklch stay saturated the whole way. The hex version ships first and the upgrade sits behind @supports.
It is still a progress bar. Every row carries role="progressbar" with its value and an aria-valuetext naming the task — the sheen is decoration and must never be the only indication that something is in progress.
Make it yours
- Retime the sheen with one duration; 2.6s is calm, 1.4s is urgent, and anything faster starts to strobe.
- Narrow the highlight band (50% → 48%/52%) for a tighter, glassier specular streak.
- Drop the glow entirely by deleting the
breatheanimation — the sheen carries the effect on its own. - Change the two gradient ends via
--aand--b; the sheen and glow both derive from them. - Pause the animation at 100% by adding
animation-play-state:pausedon a completed row, so "done" looks settled. - Use it as a single hero bar by keeping one row and doubling the track height to 1.1rem.
Gotchas — read before shipping
- A sheen built as a separate absolutely positioned element needs its own
overflow:hiddenparent or it escapes the rounded fill. - Animating
box-shadowon many elements at once is a real paint cost. One glowing element per view, slow cycle. - sRGB gradients between distant hues pass through grey. Use
oklchwhere supported, and pick mid-stops manually where it is not. background-sizelarger than 100% is what makes the sheen travel; without itbackground-positionhas nowhere to go.- Infinite ambient motion next to text is a vestibular trigger — the reduced-motion block is not optional here.
- Do not let the sheen imply activity on a finished bar. Pause it at 100% or users will keep waiting.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 121+ | 114+ |
Floor set by :has(), oklch(), color-mix(), backdrop-filter, text-wrap as this demo is written. The core technique itself goes back further — Chrome 26+.
Gradient and background-position animation are universally supported. oklch() (Chrome 111, Safari 15.4, Firefox 113) and color-mix() only refine the palette, behind @supports with hex declared first.