03 / 22
All 22 in 22 CSS Avatars
- 01CSS Circular Avatar with Border Ring
- 02CSS Squircle Avatar
- 03CSS Gradient Ring Avatar
- 04CSS Conic Gradient Story Ring Avatar
- 05CSS Hexagon Avatar with clip-path
- 06CSS Avatar with Online Status Dot
- 07CSS Avatar with Notification Count Badge
- 08CSS Avatar with Verified Checkmark Badge
- 09CSS Typing Presence Pulse Avatar
- 10CSS Stacked Avatar Group with Overlap
- 11CSS Avatar Group with Plus-N Overflow Count
- 12CSS Team Avatar Row with Hover Spread
- 13CSS Avatar List with Name and Role
- 14CSS Initials Avatar with Generated Background
- 15CSS Avatar Fallback for Broken Images
- 16CSS Letter Avatar Color Palette Set
- 17CSS Avatar with Hover Profile Card
- 18CSS Avatar Upload with Hover Overlay
- 19CSS Avatar Picker Grid
- 20CSS Skeleton Loading Avatar
- 21CSS Avatar Size Scale System
- 22CSS Comment Thread Avatar Layout
CSS Gradient Ring Avatar
A gradient cannot go in a box-shadow and border-image refuses to follow border-radius — so the ring is built from two stacked backgrounds clipped differently: the surface colour clipped to padding-box, the gradient clipped to border-box, with a transparent border as the gap between them. Three colourways, one shared structure, and a hover that rotates the gradient rather than repainting it.
Build UI like this from scratch: Flexbox, Grid, animations & responsive CSS
ZTM · The CSS Bootcamp · 30‑day money-back guarantee · Affiliate link
The code
<div class="av-03">
<input class="av-03__sr" type="checkbox" id="av-03-dark">
<label class="av-03__theme" for="av-03-dark">
<svg class="av-03__i av-03__i--moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.4 8.4 0 0 1 9.7 3.5a8.5 8.5 0 1 0 10.8 10.8Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>
<svg class="av-03__i av-03__i--sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.1" stroke="currentColor" stroke-width="1.7"/><path d="M12 3.2v2M12 18.8v2M3.2 12h2M18.8 12h2M5.7 5.7l1.4 1.4M16.9 16.9l1.4 1.4M18.3 5.7l-1.4 1.4M7.1 16.9l-1.4 1.4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
<span class="av-03__vh">Dark theme</span>
</label>
<div class="av-03__stage">
<section class="av-03__wrap" aria-labelledby="av-03-h">
<header class="av-03__head">
<p class="av-03__eyebrow">Identity · Avatar</p>
<h2 class="av-03__h" id="av-03-h">Gradient rings</h2>
<p class="av-03__sub">Two backgrounds, two clip boxes, one transparent border. Hover to sweep the ring.</p>
</header>
<ul class="av-03__row">
<li class="av-03__item av-03__item--aurora">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1607746882042-944635dfe10e?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Zoe Alvarez</span>
<span class="av-03__role">Aurora</span>
</span>
</a>
</li>
<li class="av-03__item av-03__item--ember">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1599566150163-29194dcaad36?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Omar Haddad</span>
<span class="av-03__role">Ember</span>
</span>
</a>
</li>
<li class="av-03__item av-03__item--mint">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Lucy Bennett</span>
<span class="av-03__role">Mint</span>
</span>
</a>
</li>
</ul>
<div class="av-03__strip">
<span class="av-03__stripfig av-03__item--aurora"><img class="av-03__img" src="https://images.unsplash.com/photo-1541823709867-1b206113eafd?w=200&auto=format&fit=facearea&facepad=2.5" alt="Freya Nilsen" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__stripfig av-03__item--ember"><img class="av-03__img" src="https://images.unsplash.com/photo-1492562080023-ab3db95bfbce?w=200&auto=format&fit=facearea&facepad=2.5" alt="Simon Wexler" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__stripfig av-03__item--mint"><img class="av-03__img" src="https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?w=200&auto=format&fit=facearea&facepad=2.5" alt="Mia Castellano" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__striptext">Same structure at 2.5rem — the ring scales with the border width.</span>
</div>
</section>
</div>
</div><div class="av-03">
<input class="av-03__sr" type="checkbox" id="av-03-dark">
<label class="av-03__theme" for="av-03-dark">
<svg class="av-03__i av-03__i--moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.4 8.4 0 0 1 9.7 3.5a8.5 8.5 0 1 0 10.8 10.8Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>
<svg class="av-03__i av-03__i--sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.1" stroke="currentColor" stroke-width="1.7"/><path d="M12 3.2v2M12 18.8v2M3.2 12h2M18.8 12h2M5.7 5.7l1.4 1.4M16.9 16.9l1.4 1.4M18.3 5.7l-1.4 1.4M7.1 16.9l-1.4 1.4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
<span class="av-03__vh">Dark theme</span>
</label>
<div class="av-03__stage">
<section class="av-03__wrap" aria-labelledby="av-03-h">
<header class="av-03__head">
<p class="av-03__eyebrow">Identity · Avatar</p>
<h2 class="av-03__h" id="av-03-h">Gradient rings</h2>
<p class="av-03__sub">Two backgrounds, two clip boxes, one transparent border. Hover to sweep the ring.</p>
</header>
<ul class="av-03__row">
<li class="av-03__item av-03__item--aurora">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1607746882042-944635dfe10e?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Zoe Alvarez</span>
<span class="av-03__role">Aurora</span>
</span>
</a>
</li>
<li class="av-03__item av-03__item--ember">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1599566150163-29194dcaad36?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Omar Haddad</span>
<span class="av-03__role">Ember</span>
</span>
</a>
</li>
<li class="av-03__item av-03__item--mint">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Lucy Bennett</span>
<span class="av-03__role">Mint</span>
</span>
</a>
</li>
</ul>
<div class="av-03__strip">
<span class="av-03__stripfig av-03__item--aurora"><img class="av-03__img" src="https://images.unsplash.com/photo-1541823709867-1b206113eafd?w=200&auto=format&fit=facearea&facepad=2.5" alt="Freya Nilsen" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__stripfig av-03__item--ember"><img class="av-03__img" src="https://images.unsplash.com/photo-1492562080023-ab3db95bfbce?w=200&auto=format&fit=facearea&facepad=2.5" alt="Simon Wexler" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__stripfig av-03__item--mint"><img class="av-03__img" src="https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?w=200&auto=format&fit=facearea&facepad=2.5" alt="Mia Castellano" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__striptext">Same structure at 2.5rem — the ring scales with the border width.</span>
</div>
</section>
</div>
</div>@supports (color: oklch(50% .1 250)) {
.av-03 {
--page: oklch(97.6% .004 265);
--panel: oklch(100% 0 0);
--panel-2: oklch(96.4% .006 265);
--ink: oklch(20% .022 265);
--muted: oklch(53% .022 265);
--line: oklch(92% .008 265);
--accent: oklch(58% .196 272);
}
.av-03__item--aurora {
--c1: oklch(70% .19 300);
--c2: oklch(78% .15 200);
--c3: oklch(72% .18 260);
}
.av-03__item--ember {
--c1: oklch(72% .19 40);
--c2: oklch(80% .16 80);
--c3: oklch(66% .21 20);
}
.av-03__item--mint {
--c1: oklch(78% .16 165);
--c2: oklch(84% .13 130);
--c3: oklch(72% .15 195);
}
}
@property --av-03-a {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
.av-03 {
--page: #f7f8fa;
--panel: #ffffff;
--panel-2: #f1f3f7;
--ink: #10131a;
--muted: #5f6672;
--line: #e4e7ee;
--accent: #4f46e5;
--glass: rgba(255,255,255,.68);
--shadow: 0 1px 2px rgba(16,19,26,.05), 0 16px 36px -20px rgba(16,19,26,.3);
--r: 18px;
--bw: 4px;
width: 100%;
inline-size: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
background: var(--page);
color: var(--ink);
font-family: system-ui,-apple-system,"Segoe UI",sans-serif;
-webkit-font-smoothing: antialiased;
}
.av-03 *,
.av-03 *::before,
.av-03 *::after {
box-sizing: border-box;
}
.av-03__vh {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.av-03__sr {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
margin: 0;
pointer-events: none;
}
.av-03__theme {
position: absolute;
inset-block-start: clamp(.85rem,2.2vw,1.5rem);
inset-inline-end: clamp(.85rem,2.2vw,1.5rem);
z-index: 20;
display: grid;
place-items: center;
inline-size: 2.5rem;
block-size: 2.5rem;
border-radius: 999px;
border: 1px solid var(--line);
background: var(--glass);
color: var(--ink);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
cursor: pointer;
transition: translate .2s ease;
}
.av-03__theme::after {
content: "";
position: absolute;
inset: -.4rem;
border-radius: inherit;
}
.av-03__theme:hover {
translate: 0 -1px;
}
.av-03__i {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.av-03__i--sun {
display: none;
}
.av-03__sr:focus-visible + .av-03__theme {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.av-03__stage {
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(1.25rem,5vw,4rem);
}
.av-03__wrap {
inline-size: min(58rem,100%);
display: flex;
flex-direction: column;
gap: clamp(1.25rem,3vw,2rem);
}
.av-03__head {
display: flex;
flex-direction: column;
gap: .4rem;
padding-inline-end: 3.5rem;
}
.av-03__eyebrow {
margin: 0;
font-size: .7rem;
font-weight: 600;
letter-spacing: .1em;
text-transform: uppercase;
color: var(--muted);
}
.av-03__h {
margin: 0;
font-size: clamp(1.6rem,4.2vw,2.4rem);
font-weight: 650;
letter-spacing: -.03em;
line-height: 1.05;
}
.av-03__sub {
margin: 0;
max-inline-size: 36rem;
font-size: .95rem;
line-height: 1.55;
color: var(--muted);
text-wrap: pretty;
}
.av-03__row {
list-style: none;
margin: 0;
padding: clamp(1.5rem,4vw,2.5rem) clamp(1rem,3vw,2rem);
display: grid;
gap: clamp(1.25rem,3vw,2rem);
grid-template-columns: repeat(auto-fit,minmax(10rem,1fr));
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--r);
box-shadow: var(--shadow);
}
.av-03__link {
display: flex;
flex-direction: column;
align-items: center;
gap: .8rem;
text-decoration: none;
color: inherit;
border-radius: 14px;
padding: .5rem;
}
.av-03__link:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.av-03__fig {
--a: var(--av-03-a);
display: grid;
inline-size: clamp(5rem,14vw,7.5rem);
aspect-ratio: 1;
padding: 0;
border: var(--bw) solid transparent;
border-radius: 50%;
background: linear-gradient(var(--panel), var(--panel)) padding-box, conic-gradient(from var(--a), var(--c1), var(--c2), var(--c3), var(--c1)) border-box;
background-origin: border-box;
transition: translate .25s cubic-bezier(.2,.7,.3,1), --av-03-a .9s linear, border-width .25s ease;
}
.av-03__img {
display: block;
inline-size: 100%;
block-size: auto;
aspect-ratio: 1;
border-radius: 50%;
object-fit: cover;
object-position: center top;
background: var(--panel-2);
}
.av-03__link:hover .av-03__fig,
.av-03__link:focus-visible .av-03__fig {
--av-03-a: 360deg;
translate: 0 -4px;
}
.av-03__who {
display: flex;
flex-direction: column;
align-items: center;
gap: .1rem;
text-align: center;
}
.av-03__name {
font-size: .95rem;
font-weight: 600;
letter-spacing: -.01em;
}
.av-03__role {
font-size: .78rem;
color: var(--muted);
}
.av-03__item--aurora {
--c1: #a855f7;
--c2: #22d3ee;
--c3: #6366f1;
}
.av-03__item--ember {
--c1: #fb7185;
--c2: #fbbf24;
--c3: #f43f5e;
}
.av-03__item--mint {
--c1: #34d399;
--c2: #a3e635;
--c3: #22d3ee;
}
.av-03__strip {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .75rem;
padding: .85rem 1rem;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 14px;
}
.av-03__stripfig {
display: block;
inline-size: 2.5rem;
aspect-ratio: 1;
border: 2px solid transparent;
border-radius: 50%;
background: linear-gradient(var(--panel), var(--panel)) padding-box, conic-gradient(from 45deg, var(--c1), var(--c2), var(--c3), var(--c1)) border-box;
background-origin: border-box;
flex: none;
}
.av-03__striptext {
font-size: .82rem;
color: var(--muted);
}
.av-03:has(#av-03-dark:checked) {
--page: #0a0b0e;
--panel: #14161c;
--panel-2: #1c1f27;
--ink: #f2f4f9;
--muted: #98a0b0;
--line: #262a33;
--accent: #8b8cf9;
--glass: rgba(255,255,255,.07);
--shadow: 0 1px 2px rgba(0,0,0,.6), 0 20px 44px -24px rgba(0,0,0,.85);
}
.av-03:has(#av-03-dark:checked) .av-03__i--moon {
display: none;
}
.av-03:has(#av-03-dark:checked) .av-03__i--sun {
display: block;
}
@media (prefers-color-scheme: dark) {
.av-03:not(:has(#av-03-dark:checked)) {
--page: #0a0b0e;
--panel: #14161c;
--panel-2: #1c1f27;
--ink: #f2f4f9;
--muted: #98a0b0;
--line: #262a33;
--accent: #8b8cf9;
--glass: rgba(255,255,255,.07);
--shadow: 0 1px 2px rgba(0,0,0,.6), 0 20px 44px -24px rgba(0,0,0,.85);
}
.av-03:not(:has(#av-03-dark:checked)) .av-03__i--moon {
display: none;
}
.av-03:not(:has(#av-03-dark:checked)) .av-03__i--sun {
display: block;
}
}
@media (prefers-reduced-motion: reduce) {
.av-03 *,
.av-03 *::before,
.av-03 *::after {
transition: none !important;
animation: none !important;
}
.av-03__link:hover .av-03__fig {
--av-03-a: 0deg;
}
}
@media (forced-colors: active) {
.av-03__fig,
.av-03__stripfig {
background: Canvas;
border-color: CanvasText;
}
.av-03__row,
.av-03__strip,
.av-03__theme {
border-color: CanvasText;
}
}@supports (color: oklch(50% .1 250)) {
.av-03 {
--page: oklch(97.6% .004 265);
--panel: oklch(100% 0 0);
--panel-2: oklch(96.4% .006 265);
--ink: oklch(20% .022 265);
--muted: oklch(53% .022 265);
--line: oklch(92% .008 265);
--accent: oklch(58% .196 272);
}
.av-03__item--aurora {
--c1: oklch(70% .19 300);
--c2: oklch(78% .15 200);
--c3: oklch(72% .18 260);
}
.av-03__item--ember {
--c1: oklch(72% .19 40);
--c2: oklch(80% .16 80);
--c3: oklch(66% .21 20);
}
.av-03__item--mint {
--c1: oklch(78% .16 165);
--c2: oklch(84% .13 130);
--c3: oklch(72% .15 195);
}
}
@property --av-03-a {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
.av-03 {
--page: #f7f8fa;
--panel: #ffffff;
--panel-2: #f1f3f7;
--ink: #10131a;
--muted: #5f6672;
--line: #e4e7ee;
--accent: #4f46e5;
--glass: rgba(255,255,255,.68);
--shadow: 0 1px 2px rgba(16,19,26,.05), 0 16px 36px -20px rgba(16,19,26,.3);
--r: 18px;
--bw: 4px;
width: 100%;
inline-size: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
background: var(--page);
color: var(--ink);
font-family: system-ui,-apple-system,"Segoe UI",sans-serif;
-webkit-font-smoothing: antialiased;
}
.av-03 *,
.av-03 *::before,
.av-03 *::after {
box-sizing: border-box;
}
.av-03__vh {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.av-03__sr {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
margin: 0;
pointer-events: none;
}
.av-03__theme {
position: absolute;
inset-block-start: clamp(.85rem,2.2vw,1.5rem);
inset-inline-end: clamp(.85rem,2.2vw,1.5rem);
z-index: 20;
display: grid;
place-items: center;
inline-size: 2.5rem;
block-size: 2.5rem;
border-radius: 999px;
border: 1px solid var(--line);
background: var(--glass);
color: var(--ink);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
cursor: pointer;
transition: translate .2s ease;
}
.av-03__theme::after {
content: "";
position: absolute;
inset: -.4rem;
border-radius: inherit;
}
.av-03__theme:hover {
translate: 0 -1px;
}
.av-03__i {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.av-03__i--sun {
display: none;
}
.av-03__sr:focus-visible + .av-03__theme {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.av-03__stage {
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(1.25rem,5vw,4rem);
}
.av-03__wrap {
inline-size: min(58rem,100%);
display: flex;
flex-direction: column;
gap: clamp(1.25rem,3vw,2rem);
}
.av-03__head {
display: flex;
flex-direction: column;
gap: .4rem;
padding-inline-end: 3.5rem;
}
.av-03__eyebrow {
margin: 0;
font-size: .7rem;
font-weight: 600;
letter-spacing: .1em;
text-transform: uppercase;
color: var(--muted);
}
.av-03__h {
margin: 0;
font-size: clamp(1.6rem,4.2vw,2.4rem);
font-weight: 650;
letter-spacing: -.03em;
line-height: 1.05;
}
.av-03__sub {
margin: 0;
max-inline-size: 36rem;
font-size: .95rem;
line-height: 1.55;
color: var(--muted);
text-wrap: pretty;
}
.av-03__row {
list-style: none;
margin: 0;
padding: clamp(1.5rem,4vw,2.5rem) clamp(1rem,3vw,2rem);
display: grid;
gap: clamp(1.25rem,3vw,2rem);
grid-template-columns: repeat(auto-fit,minmax(10rem,1fr));
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--r);
box-shadow: var(--shadow);
}
.av-03__link {
display: flex;
flex-direction: column;
align-items: center;
gap: .8rem;
text-decoration: none;
color: inherit;
border-radius: 14px;
padding: .5rem;
}
.av-03__link:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.av-03__fig {
--a: var(--av-03-a);
display: grid;
inline-size: clamp(5rem,14vw,7.5rem);
aspect-ratio: 1;
padding: 0;
border: var(--bw) solid transparent;
border-radius: 50%;
background: linear-gradient(var(--panel), var(--panel)) padding-box, conic-gradient(from var(--a), var(--c1), var(--c2), var(--c3), var(--c1)) border-box;
background-origin: border-box;
transition: translate .25s cubic-bezier(.2,.7,.3,1), --av-03-a .9s linear, border-width .25s ease;
}
.av-03__img {
display: block;
inline-size: 100%;
block-size: auto;
aspect-ratio: 1;
border-radius: 50%;
object-fit: cover;
object-position: center top;
background: var(--panel-2);
}
.av-03__link:hover .av-03__fig,
.av-03__link:focus-visible .av-03__fig {
--av-03-a: 360deg;
translate: 0 -4px;
}
.av-03__who {
display: flex;
flex-direction: column;
align-items: center;
gap: .1rem;
text-align: center;
}
.av-03__name {
font-size: .95rem;
font-weight: 600;
letter-spacing: -.01em;
}
.av-03__role {
font-size: .78rem;
color: var(--muted);
}
.av-03__item--aurora {
--c1: #a855f7;
--c2: #22d3ee;
--c3: #6366f1;
}
.av-03__item--ember {
--c1: #fb7185;
--c2: #fbbf24;
--c3: #f43f5e;
}
.av-03__item--mint {
--c1: #34d399;
--c2: #a3e635;
--c3: #22d3ee;
}
.av-03__strip {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .75rem;
padding: .85rem 1rem;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 14px;
}
.av-03__stripfig {
display: block;
inline-size: 2.5rem;
aspect-ratio: 1;
border: 2px solid transparent;
border-radius: 50%;
background: linear-gradient(var(--panel), var(--panel)) padding-box, conic-gradient(from 45deg, var(--c1), var(--c2), var(--c3), var(--c1)) border-box;
background-origin: border-box;
flex: none;
}
.av-03__striptext {
font-size: .82rem;
color: var(--muted);
}
.av-03:has(#av-03-dark:checked) {
--page: #0a0b0e;
--panel: #14161c;
--panel-2: #1c1f27;
--ink: #f2f4f9;
--muted: #98a0b0;
--line: #262a33;
--accent: #8b8cf9;
--glass: rgba(255,255,255,.07);
--shadow: 0 1px 2px rgba(0,0,0,.6), 0 20px 44px -24px rgba(0,0,0,.85);
}
.av-03:has(#av-03-dark:checked) .av-03__i--moon {
display: none;
}
.av-03:has(#av-03-dark:checked) .av-03__i--sun {
display: block;
}
@media (prefers-color-scheme: dark) {
.av-03:not(:has(#av-03-dark:checked)) {
--page: #0a0b0e;
--panel: #14161c;
--panel-2: #1c1f27;
--ink: #f2f4f9;
--muted: #98a0b0;
--line: #262a33;
--accent: #8b8cf9;
--glass: rgba(255,255,255,.07);
--shadow: 0 1px 2px rgba(0,0,0,.6), 0 20px 44px -24px rgba(0,0,0,.85);
}
.av-03:not(:has(#av-03-dark:checked)) .av-03__i--moon {
display: none;
}
.av-03:not(:has(#av-03-dark:checked)) .av-03__i--sun {
display: block;
}
}
@media (prefers-reduced-motion: reduce) {
.av-03 *,
.av-03 *::before,
.av-03 *::after {
transition: none !important;
animation: none !important;
}
.av-03__link:hover .av-03__fig {
--av-03-a: 0deg;
}
}
@media (forced-colors: active) {
.av-03__fig,
.av-03__stripfig {
background: Canvas;
border-color: CanvasText;
}
.av-03__row,
.av-03__strip,
.av-03__theme {
border-color: CanvasText;
}
}Here's a working CSS Avatar 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: CSS Gradient Ring Avatar
Source: https://codefronts.com/components/css-avatars/css-gradient-ring-avatar/
A gradient cannot go in a box-shadow and border-image refuses to follow border-radius — so the ring is built from two stacked backgrounds clipped differently: the surface colour clipped to padding-box, the gradient clipped to border-box, with a transparent border as the gap between them. Three colourways, one shared structure, and a hover that rotates the gradient rather than repainting it.
## HTML
```html
<div class="av-03">
<input class="av-03__sr" type="checkbox" id="av-03-dark">
<label class="av-03__theme" for="av-03-dark">
<svg class="av-03__i av-03__i--moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.4 8.4 0 0 1 9.7 3.5a8.5 8.5 0 1 0 10.8 10.8Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>
<svg class="av-03__i av-03__i--sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.1" stroke="currentColor" stroke-width="1.7"/><path d="M12 3.2v2M12 18.8v2M3.2 12h2M18.8 12h2M5.7 5.7l1.4 1.4M16.9 16.9l1.4 1.4M18.3 5.7l-1.4 1.4M7.1 16.9l-1.4 1.4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
<span class="av-03__vh">Dark theme</span>
</label>
<div class="av-03__stage">
<section class="av-03__wrap" aria-labelledby="av-03-h">
<header class="av-03__head">
<p class="av-03__eyebrow">Identity · Avatar</p>
<h2 class="av-03__h" id="av-03-h">Gradient rings</h2>
<p class="av-03__sub">Two backgrounds, two clip boxes, one transparent border. Hover to sweep the ring.</p>
</header>
<ul class="av-03__row">
<li class="av-03__item av-03__item--aurora">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1607746882042-944635dfe10e?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Zoe Alvarez</span>
<span class="av-03__role">Aurora</span>
</span>
</a>
</li>
<li class="av-03__item av-03__item--ember">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1599566150163-29194dcaad36?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Omar Haddad</span>
<span class="av-03__role">Ember</span>
</span>
</a>
</li>
<li class="av-03__item av-03__item--mint">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Lucy Bennett</span>
<span class="av-03__role">Mint</span>
</span>
</a>
</li>
</ul>
<div class="av-03__strip">
<span class="av-03__stripfig av-03__item--aurora"><img class="av-03__img" src="https://images.unsplash.com/photo-1541823709867-1b206113eafd?w=200&auto=format&fit=facearea&facepad=2.5" alt="Freya Nilsen" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__stripfig av-03__item--ember"><img class="av-03__img" src="https://images.unsplash.com/photo-1492562080023-ab3db95bfbce?w=200&auto=format&fit=facearea&facepad=2.5" alt="Simon Wexler" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__stripfig av-03__item--mint"><img class="av-03__img" src="https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?w=200&auto=format&fit=facearea&facepad=2.5" alt="Mia Castellano" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__striptext">Same structure at 2.5rem — the ring scales with the border width.</span>
</div>
</section>
</div>
</div>
```
## CSS
```css
@supports (color: oklch(50% .1 250)) {
.av-03 {
--page: oklch(97.6% .004 265);
--panel: oklch(100% 0 0);
--panel-2: oklch(96.4% .006 265);
--ink: oklch(20% .022 265);
--muted: oklch(53% .022 265);
--line: oklch(92% .008 265);
--accent: oklch(58% .196 272);
}
.av-03__item--aurora {
--c1: oklch(70% .19 300);
--c2: oklch(78% .15 200);
--c3: oklch(72% .18 260);
}
.av-03__item--ember {
--c1: oklch(72% .19 40);
--c2: oklch(80% .16 80);
--c3: oklch(66% .21 20);
}
.av-03__item--mint {
--c1: oklch(78% .16 165);
--c2: oklch(84% .13 130);
--c3: oklch(72% .15 195);
}
}
@property --av-03-a {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
.av-03 {
--page: #f7f8fa;
--panel: #ffffff;
--panel-2: #f1f3f7;
--ink: #10131a;
--muted: #5f6672;
--line: #e4e7ee;
--accent: #4f46e5;
--glass: rgba(255,255,255,.68);
--shadow: 0 1px 2px rgba(16,19,26,.05), 0 16px 36px -20px rgba(16,19,26,.3);
--r: 18px;
--bw: 4px;
width: 100%;
inline-size: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
background: var(--page);
color: var(--ink);
font-family: system-ui,-apple-system,"Segoe UI",sans-serif;
-webkit-font-smoothing: antialiased;
}
.av-03 *,
.av-03 *::before,
.av-03 *::after {
box-sizing: border-box;
}
.av-03__vh {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.av-03__sr {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
margin: 0;
pointer-events: none;
}
.av-03__theme {
position: absolute;
inset-block-start: clamp(.85rem,2.2vw,1.5rem);
inset-inline-end: clamp(.85rem,2.2vw,1.5rem);
z-index: 20;
display: grid;
place-items: center;
inline-size: 2.5rem;
block-size: 2.5rem;
border-radius: 999px;
border: 1px solid var(--line);
background: var(--glass);
color: var(--ink);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
cursor: pointer;
transition: translate .2s ease;
}
.av-03__theme::after {
content: "";
position: absolute;
inset: -.4rem;
border-radius: inherit;
}
.av-03__theme:hover {
translate: 0 -1px;
}
.av-03__i {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.av-03__i--sun {
display: none;
}
.av-03__sr:focus-visible + .av-03__theme {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.av-03__stage {
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(1.25rem,5vw,4rem);
}
.av-03__wrap {
inline-size: min(58rem,100%);
display: flex;
flex-direction: column;
gap: clamp(1.25rem,3vw,2rem);
}
.av-03__head {
display: flex;
flex-direction: column;
gap: .4rem;
padding-inline-end: 3.5rem;
}
.av-03__eyebrow {
margin: 0;
font-size: .7rem;
font-weight: 600;
letter-spacing: .1em;
text-transform: uppercase;
color: var(--muted);
}
.av-03__h {
margin: 0;
font-size: clamp(1.6rem,4.2vw,2.4rem);
font-weight: 650;
letter-spacing: -.03em;
line-height: 1.05;
}
.av-03__sub {
margin: 0;
max-inline-size: 36rem;
font-size: .95rem;
line-height: 1.55;
color: var(--muted);
text-wrap: pretty;
}
.av-03__row {
list-style: none;
margin: 0;
padding: clamp(1.5rem,4vw,2.5rem) clamp(1rem,3vw,2rem);
display: grid;
gap: clamp(1.25rem,3vw,2rem);
grid-template-columns: repeat(auto-fit,minmax(10rem,1fr));
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--r);
box-shadow: var(--shadow);
}
.av-03__link {
display: flex;
flex-direction: column;
align-items: center;
gap: .8rem;
text-decoration: none;
color: inherit;
border-radius: 14px;
padding: .5rem;
}
.av-03__link:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.av-03__fig {
--a: var(--av-03-a);
display: grid;
inline-size: clamp(5rem,14vw,7.5rem);
aspect-ratio: 1;
padding: 0;
border: var(--bw) solid transparent;
border-radius: 50%;
background: linear-gradient(var(--panel), var(--panel)) padding-box, conic-gradient(from var(--a), var(--c1), var(--c2), var(--c3), var(--c1)) border-box;
background-origin: border-box;
transition: translate .25s cubic-bezier(.2,.7,.3,1), --av-03-a .9s linear, border-width .25s ease;
}
.av-03__img {
display: block;
inline-size: 100%;
block-size: auto;
aspect-ratio: 1;
border-radius: 50%;
object-fit: cover;
object-position: center top;
background: var(--panel-2);
}
.av-03__link:hover .av-03__fig,
.av-03__link:focus-visible .av-03__fig {
--av-03-a: 360deg;
translate: 0 -4px;
}
.av-03__who {
display: flex;
flex-direction: column;
align-items: center;
gap: .1rem;
text-align: center;
}
.av-03__name {
font-size: .95rem;
font-weight: 600;
letter-spacing: -.01em;
}
.av-03__role {
font-size: .78rem;
color: var(--muted);
}
.av-03__item--aurora {
--c1: #a855f7;
--c2: #22d3ee;
--c3: #6366f1;
}
.av-03__item--ember {
--c1: #fb7185;
--c2: #fbbf24;
--c3: #f43f5e;
}
.av-03__item--mint {
--c1: #34d399;
--c2: #a3e635;
--c3: #22d3ee;
}
.av-03__strip {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .75rem;
padding: .85rem 1rem;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 14px;
}
.av-03__stripfig {
display: block;
inline-size: 2.5rem;
aspect-ratio: 1;
border: 2px solid transparent;
border-radius: 50%;
background: linear-gradient(var(--panel), var(--panel)) padding-box, conic-gradient(from 45deg, var(--c1), var(--c2), var(--c3), var(--c1)) border-box;
background-origin: border-box;
flex: none;
}
.av-03__striptext {
font-size: .82rem;
color: var(--muted);
}
.av-03:has(#av-03-dark:checked) {
--page: #0a0b0e;
--panel: #14161c;
--panel-2: #1c1f27;
--ink: #f2f4f9;
--muted: #98a0b0;
--line: #262a33;
--accent: #8b8cf9;
--glass: rgba(255,255,255,.07);
--shadow: 0 1px 2px rgba(0,0,0,.6), 0 20px 44px -24px rgba(0,0,0,.85);
}
.av-03:has(#av-03-dark:checked) .av-03__i--moon {
display: none;
}
.av-03:has(#av-03-dark:checked) .av-03__i--sun {
display: block;
}
@media (prefers-color-scheme: dark) {
.av-03:not(:has(#av-03-dark:checked)) {
--page: #0a0b0e;
--panel: #14161c;
--panel-2: #1c1f27;
--ink: #f2f4f9;
--muted: #98a0b0;
--line: #262a33;
--accent: #8b8cf9;
--glass: rgba(255,255,255,.07);
--shadow: 0 1px 2px rgba(0,0,0,.6), 0 20px 44px -24px rgba(0,0,0,.85);
}
.av-03:not(:has(#av-03-dark:checked)) .av-03__i--moon {
display: none;
}
.av-03:not(:has(#av-03-dark:checked)) .av-03__i--sun {
display: block;
}
}
@media (prefers-reduced-motion: reduce) {
.av-03 *,
.av-03 *::before,
.av-03 *::after {
transition: none !important;
animation: none !important;
}
.av-03__link:hover .av-03__fig {
--av-03-a: 0deg;
}
}
@media (forced-colors: active) {
.av-03__fig,
.av-03__stripfig {
background: Canvas;
border-color: CanvasText;
}
.av-03__row,
.av-03__strip,
.av-03__theme {
border-color: CanvasText;
}
}
```Here's a working CSS Avatar 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: CSS Gradient Ring Avatar
Source: https://codefronts.com/components/css-avatars/css-gradient-ring-avatar/
A gradient cannot go in a box-shadow and border-image refuses to follow border-radius — so the ring is built from two stacked backgrounds clipped differently: the surface colour clipped to padding-box, the gradient clipped to border-box, with a transparent border as the gap between them. Three colourways, one shared structure, and a hover that rotates the gradient rather than repainting it.
## HTML
```html
<div class="av-03">
<input class="av-03__sr" type="checkbox" id="av-03-dark">
<label class="av-03__theme" for="av-03-dark">
<svg class="av-03__i av-03__i--moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.4 8.4 0 0 1 9.7 3.5a8.5 8.5 0 1 0 10.8 10.8Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>
<svg class="av-03__i av-03__i--sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.1" stroke="currentColor" stroke-width="1.7"/><path d="M12 3.2v2M12 18.8v2M3.2 12h2M18.8 12h2M5.7 5.7l1.4 1.4M16.9 16.9l1.4 1.4M18.3 5.7l-1.4 1.4M7.1 16.9l-1.4 1.4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
<span class="av-03__vh">Dark theme</span>
</label>
<div class="av-03__stage">
<section class="av-03__wrap" aria-labelledby="av-03-h">
<header class="av-03__head">
<p class="av-03__eyebrow">Identity · Avatar</p>
<h2 class="av-03__h" id="av-03-h">Gradient rings</h2>
<p class="av-03__sub">Two backgrounds, two clip boxes, one transparent border. Hover to sweep the ring.</p>
</header>
<ul class="av-03__row">
<li class="av-03__item av-03__item--aurora">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1607746882042-944635dfe10e?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Zoe Alvarez</span>
<span class="av-03__role">Aurora</span>
</span>
</a>
</li>
<li class="av-03__item av-03__item--ember">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1599566150163-29194dcaad36?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Omar Haddad</span>
<span class="av-03__role">Ember</span>
</span>
</a>
</li>
<li class="av-03__item av-03__item--mint">
<a class="av-03__link" href="#av-03-h">
<span class="av-03__fig" aria-hidden="true">
<img class="av-03__img" src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?w=200&auto=format&fit=facearea&facepad=2.5" alt="" width="200" height="200" loading="lazy" decoding="async">
</span>
<span class="av-03__who">
<span class="av-03__name">Lucy Bennett</span>
<span class="av-03__role">Mint</span>
</span>
</a>
</li>
</ul>
<div class="av-03__strip">
<span class="av-03__stripfig av-03__item--aurora"><img class="av-03__img" src="https://images.unsplash.com/photo-1541823709867-1b206113eafd?w=200&auto=format&fit=facearea&facepad=2.5" alt="Freya Nilsen" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__stripfig av-03__item--ember"><img class="av-03__img" src="https://images.unsplash.com/photo-1492562080023-ab3db95bfbce?w=200&auto=format&fit=facearea&facepad=2.5" alt="Simon Wexler" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__stripfig av-03__item--mint"><img class="av-03__img" src="https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?w=200&auto=format&fit=facearea&facepad=2.5" alt="Mia Castellano" width="200" height="200" loading="lazy" decoding="async"></span>
<span class="av-03__striptext">Same structure at 2.5rem — the ring scales with the border width.</span>
</div>
</section>
</div>
</div>
```
## CSS
```css
@supports (color: oklch(50% .1 250)) {
.av-03 {
--page: oklch(97.6% .004 265);
--panel: oklch(100% 0 0);
--panel-2: oklch(96.4% .006 265);
--ink: oklch(20% .022 265);
--muted: oklch(53% .022 265);
--line: oklch(92% .008 265);
--accent: oklch(58% .196 272);
}
.av-03__item--aurora {
--c1: oklch(70% .19 300);
--c2: oklch(78% .15 200);
--c3: oklch(72% .18 260);
}
.av-03__item--ember {
--c1: oklch(72% .19 40);
--c2: oklch(80% .16 80);
--c3: oklch(66% .21 20);
}
.av-03__item--mint {
--c1: oklch(78% .16 165);
--c2: oklch(84% .13 130);
--c3: oklch(72% .15 195);
}
}
@property --av-03-a {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
.av-03 {
--page: #f7f8fa;
--panel: #ffffff;
--panel-2: #f1f3f7;
--ink: #10131a;
--muted: #5f6672;
--line: #e4e7ee;
--accent: #4f46e5;
--glass: rgba(255,255,255,.68);
--shadow: 0 1px 2px rgba(16,19,26,.05), 0 16px 36px -20px rgba(16,19,26,.3);
--r: 18px;
--bw: 4px;
width: 100%;
inline-size: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
background: var(--page);
color: var(--ink);
font-family: system-ui,-apple-system,"Segoe UI",sans-serif;
-webkit-font-smoothing: antialiased;
}
.av-03 *,
.av-03 *::before,
.av-03 *::after {
box-sizing: border-box;
}
.av-03__vh {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.av-03__sr {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
margin: 0;
pointer-events: none;
}
.av-03__theme {
position: absolute;
inset-block-start: clamp(.85rem,2.2vw,1.5rem);
inset-inline-end: clamp(.85rem,2.2vw,1.5rem);
z-index: 20;
display: grid;
place-items: center;
inline-size: 2.5rem;
block-size: 2.5rem;
border-radius: 999px;
border: 1px solid var(--line);
background: var(--glass);
color: var(--ink);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
cursor: pointer;
transition: translate .2s ease;
}
.av-03__theme::after {
content: "";
position: absolute;
inset: -.4rem;
border-radius: inherit;
}
.av-03__theme:hover {
translate: 0 -1px;
}
.av-03__i {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.av-03__i--sun {
display: none;
}
.av-03__sr:focus-visible + .av-03__theme {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.av-03__stage {
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(1.25rem,5vw,4rem);
}
.av-03__wrap {
inline-size: min(58rem,100%);
display: flex;
flex-direction: column;
gap: clamp(1.25rem,3vw,2rem);
}
.av-03__head {
display: flex;
flex-direction: column;
gap: .4rem;
padding-inline-end: 3.5rem;
}
.av-03__eyebrow {
margin: 0;
font-size: .7rem;
font-weight: 600;
letter-spacing: .1em;
text-transform: uppercase;
color: var(--muted);
}
.av-03__h {
margin: 0;
font-size: clamp(1.6rem,4.2vw,2.4rem);
font-weight: 650;
letter-spacing: -.03em;
line-height: 1.05;
}
.av-03__sub {
margin: 0;
max-inline-size: 36rem;
font-size: .95rem;
line-height: 1.55;
color: var(--muted);
text-wrap: pretty;
}
.av-03__row {
list-style: none;
margin: 0;
padding: clamp(1.5rem,4vw,2.5rem) clamp(1rem,3vw,2rem);
display: grid;
gap: clamp(1.25rem,3vw,2rem);
grid-template-columns: repeat(auto-fit,minmax(10rem,1fr));
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--r);
box-shadow: var(--shadow);
}
.av-03__link {
display: flex;
flex-direction: column;
align-items: center;
gap: .8rem;
text-decoration: none;
color: inherit;
border-radius: 14px;
padding: .5rem;
}
.av-03__link:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.av-03__fig {
--a: var(--av-03-a);
display: grid;
inline-size: clamp(5rem,14vw,7.5rem);
aspect-ratio: 1;
padding: 0;
border: var(--bw) solid transparent;
border-radius: 50%;
background: linear-gradient(var(--panel), var(--panel)) padding-box, conic-gradient(from var(--a), var(--c1), var(--c2), var(--c3), var(--c1)) border-box;
background-origin: border-box;
transition: translate .25s cubic-bezier(.2,.7,.3,1), --av-03-a .9s linear, border-width .25s ease;
}
.av-03__img {
display: block;
inline-size: 100%;
block-size: auto;
aspect-ratio: 1;
border-radius: 50%;
object-fit: cover;
object-position: center top;
background: var(--panel-2);
}
.av-03__link:hover .av-03__fig,
.av-03__link:focus-visible .av-03__fig {
--av-03-a: 360deg;
translate: 0 -4px;
}
.av-03__who {
display: flex;
flex-direction: column;
align-items: center;
gap: .1rem;
text-align: center;
}
.av-03__name {
font-size: .95rem;
font-weight: 600;
letter-spacing: -.01em;
}
.av-03__role {
font-size: .78rem;
color: var(--muted);
}
.av-03__item--aurora {
--c1: #a855f7;
--c2: #22d3ee;
--c3: #6366f1;
}
.av-03__item--ember {
--c1: #fb7185;
--c2: #fbbf24;
--c3: #f43f5e;
}
.av-03__item--mint {
--c1: #34d399;
--c2: #a3e635;
--c3: #22d3ee;
}
.av-03__strip {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .75rem;
padding: .85rem 1rem;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 14px;
}
.av-03__stripfig {
display: block;
inline-size: 2.5rem;
aspect-ratio: 1;
border: 2px solid transparent;
border-radius: 50%;
background: linear-gradient(var(--panel), var(--panel)) padding-box, conic-gradient(from 45deg, var(--c1), var(--c2), var(--c3), var(--c1)) border-box;
background-origin: border-box;
flex: none;
}
.av-03__striptext {
font-size: .82rem;
color: var(--muted);
}
.av-03:has(#av-03-dark:checked) {
--page: #0a0b0e;
--panel: #14161c;
--panel-2: #1c1f27;
--ink: #f2f4f9;
--muted: #98a0b0;
--line: #262a33;
--accent: #8b8cf9;
--glass: rgba(255,255,255,.07);
--shadow: 0 1px 2px rgba(0,0,0,.6), 0 20px 44px -24px rgba(0,0,0,.85);
}
.av-03:has(#av-03-dark:checked) .av-03__i--moon {
display: none;
}
.av-03:has(#av-03-dark:checked) .av-03__i--sun {
display: block;
}
@media (prefers-color-scheme: dark) {
.av-03:not(:has(#av-03-dark:checked)) {
--page: #0a0b0e;
--panel: #14161c;
--panel-2: #1c1f27;
--ink: #f2f4f9;
--muted: #98a0b0;
--line: #262a33;
--accent: #8b8cf9;
--glass: rgba(255,255,255,.07);
--shadow: 0 1px 2px rgba(0,0,0,.6), 0 20px 44px -24px rgba(0,0,0,.85);
}
.av-03:not(:has(#av-03-dark:checked)) .av-03__i--moon {
display: none;
}
.av-03:not(:has(#av-03-dark:checked)) .av-03__i--sun {
display: block;
}
}
@media (prefers-reduced-motion: reduce) {
.av-03 *,
.av-03 *::before,
.av-03 *::after {
transition: none !important;
animation: none !important;
}
.av-03__link:hover .av-03__fig {
--av-03-a: 0deg;
}
}
@media (forced-colors: active) {
.av-03__fig,
.av-03__stripfig {
background: Canvas;
border-color: CanvasText;
}
.av-03__row,
.av-03__strip,
.av-03__theme {
border-color: CanvasText;
}
}
```How this works
Why the obvious approaches fail. box-shadow only takes flat colours. border-image ignores border-radius, so a gradient border on a circle renders as a square frame. outline has the same limitation. The technique that works stacks two backgrounds on the same element and clips them to different boxes:
.av-03__fig{
border: 4px solid transparent; /* the ring channel */
border-radius: 50%;
background:
linear-gradient(var(--panel), var(--panel)) padding-box,
conic-gradient(from var(--a), var(--c1), var(--c2), var(--c3), var(--c1)) border-box;
}The first layer — a flat colour faked as a gradient, because background-clip only applies to background images — fills the padding box and hides the middle of the second layer. The second layer fills the border box, so all that remains visible of it is the 4px border ring.
Making it animate. A custom property is a string by default, so --a: 0deg → 360deg cannot tween. Registering it teaches the browser its type, and the sweep becomes a real compositor-friendly animation:
@property --av-03-a{ syntax:'<angle>'; inherits:false; initial-value:0deg; }
.av-03__item:hover .av-03__fig{ --a: 360deg; transition: --av-03-a .9s linear; }Colourways are tokens. Each variant sets only --c1/--c2/--c3; the structure is identical, which is what makes this scale to a real design system. Stops are authored in oklch() so a violet→cyan blend does not pass through grey the way sRGB interpolation does — with hex stops declared first for older engines.
Make it yours
- Change ring thickness with the
border-widthalone — the gradient re-measures itself becausebackground-originis the border box. - Swap
conic-gradientforlinear-gradient(135deg, …)for a flat two-stop ring, or add a fourth stop for a longer sweep. - Add a gap between photo and ring by nesting a second element with its own padding, or by increasing the padding-box layer's inset with an extra
box-shadow: 0 0 0 2px var(--panel)inside. - Rethemeable in one place: define
--c1/--c2/--c3at app level and every gradient avatar follows brand. - For a static ring, drop the
@propertyblock entirely — the two-background structure needs no registration. - On a tinted card, update the
padding-boxlayer colour (--panel) so the inner disc matches its surface instead of punching a white hole.
Gotchas — read before shipping
background-cliphas no effect on a plainbackground-color. The inner layer must be an image — hencelinear-gradient(var(--panel), var(--panel)).- Layer order matters:
padding-boxfirst (painted on top),border-boxsecond. Reverse them and the gradient covers the photo. - The border must be
transparent, notnone—nonecomputes the width to zero and the ring vanishes. - Without
@property, the hover sweep snaps instantly. Register the angle, or animaterotateon a pseudo-element instead. - An
<img>child needs its ownborder-radius: inherit(oroverflow: hiddenon the wrapper), or its square corners will cross the ring. - Don't animate the gradient on load by default — a permanently rotating ring is visual noise and must be disabled under
prefers-reduced-motion.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 128+ | 114+ |
Floor set by :has(), oklch(), backdrop-filter, @property, text-wrap as this demo is written. The core technique itself goes back further — Chrome 105+.
The two-background gradient-border technique works in every browser since 2015. @property (Chrome 85 / Safari 16.4 / Firefox 128) is required only for the animated sweep and is gated with @supports — older engines get the same static ring. oklch() stops sit behind @supports with hex declared first; :has() drives the CSS-only theme toggle.