22 CSS Avatars

22 hand-coded CSS avatars for chat apps, team dashboards, comment threads, account menus and social profiles. Covers ring and squircle shapes, online status dots, verified badges, stacked facepiles with plus-N overflow, initials fallbacks for missing photos, broken-image recovery, and a size scale where the ring, badge and status dot all scale from one custom property. Scoped under .av-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.

16 pure CSS6 light JSPublished

Related20 CSS Profile Cards30 CSS Notifications15 CSS Chat Bubbles30 CSS Badges

CSS Circular Avatar with Border Ring — preview
01 / 22Pure CSS

CSS Circular Avatar with Border Ring

The production default, done properly: the ring is a box-shadow spread rather than a border, so it paints outside the box and costs zero layout — swap a 2px ring for a 6px one and nothing in the row moves. Three treatments sit side by side (solid, offset-gap, double) and a real radio group retunes ring width live through one custom property, with no JavaScript.

Published

CSS Squircle Avatar — preview
02 / 22Pure CSS

CSS Squircle Avatar

The iOS/Figma superellipse, now a real CSS corner shape. corner-shape: squircle curves the corner continuously instead of arcing it, which is why an app icon looks softer than a border-radius rectangle at the same radius. The demo puts squircle and plain rounded-rect side by side at matched radii so the difference actually reads, and a radio group cycles every corner-shape value — round, squircle, bevel, notch, scoop — with a tuned border-radius: 30% fallback everywhere the property is unsupported.

Published

CSS Gradient Ring Avatar — preview
03 / 22Pure CSS

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.

Published

CSS Conic Gradient Story Ring Avatar — preview
04 / 22Pure CSS

CSS Conic Gradient Story Ring Avatar

The story-ring pattern with the state model people actually forget: unread is a saturated conic sweep on a slow rotation, seen is a flat grey static ring, and each carries visually-hidden text so the difference is not purely visual. Rotation lives on a pseudo-element so the ring spins while the photo stays perfectly still, and it stops dead under prefers-reduced-motion.

Published

CSS Hexagon Avatar with clip-path — preview
05 / 22Pure CSS

CSS Hexagon Avatar with clip-path

A gaming/esports roster where every face is a clip-path hexagon — and a working answer to the bug everyone hits: clip-path clips pseudo-elements and shadows too, so the rank badge and status dot live on an unclipped wrapper, never on the clipped element. The hex ring is a second, slightly larger clipped layer behind the first, which is the only way to outline a clipped shape.

Published

CSS Avatar with Online Status Dot — preview
06 / 22Pure CSS

CSS Avatar with Online Status Dot

Presence done to spec: a dot at the bottom-right with a ring of surface colour so it reads on any photo, in four states — online, away, busy, offline — where each state is distinguished by an inline-SVG glyph and visually-hidden text, never by hue alone. A real radio group sets your own presence and every dependent surface updates through :has(), with zero JavaScript.

Published

CSS Avatar with Notification Count Badge — preview
07 / 22Light JS

CSS Avatar with Notification Count Badge

The count badge that survives real data: 1 digit, 2 digits and 99+ all render without the badge jumping, because the pill is a min-inline-size circle that grows only when the text demands it, and the digits are tabular-nums so a 7 is exactly as wide as a 1. The real number goes to assistive tech through aria-label — never inferred from the visual text — and the count is live, so you can watch the width behave.

Published

CSS Avatar with Verified Checkmark Badge — preview
08 / 22Pure CSS

CSS Avatar with Verified Checkmark Badge

The platform verification tick, engineered rather than pasted: an inline-SVG check on a coloured disc, notched into the avatar edge with a ring of surface colour so it reads as cut into the photo. Three tiers — verified, official, staff — each with its own glyph and its own visible text, because a blue disc alone means nothing to a screen reader or to anyone who cannot separate blue from grey.

Published

CSS Typing Presence Pulse Avatar — preview
09 / 22Pure CSS

CSS Typing Presence Pulse Avatar

"Alex is typing" as an avatar state rather than a line of text: two offset pulse rings expand out of the avatar on a 2.4s loop, animating only scale and opacity so the whole effect stays on the compositor. The three typing dots use the same staggered timing, presence is still announced in words for assistive tech, and everything stops completely under prefers-reduced-motion — a slower pulse is still a pulse.

Published

CSS Stacked Avatar Group with Overlap — preview
10 / 22Pure CSS

CSS Stacked Avatar Group with Overlap

The canonical facepile, with the two details that separate a good one from a broken one: ring separation (a spread of surface colour so neighbours don't smear together) and deliberate z-order so the first avatar sits on top instead of last-wins. Three densities (3, 5 and 8 faces) and a live overlap control, all in CSS — the stack tightens as the count grows, exactly as it should.

Published

CSS Avatar Group with Plus-N Overflow Count — preview
11 / 22Pure CSS

CSS Avatar Group with Plus-N Overflow Count

A facepile that tells the truth about how many people are in the room: the final slot is a +N chip built to exactly the avatar's dimensions — same size token, same ring, same stack position — so the row's rhythm never breaks. The chip is a real <button> with the full count in its accessible name, and it expands the hidden members with pure CSS via a checkbox and :has().

Published

CSS Team Avatar Row with Hover Spread — preview
12 / 22Pure CSS

CSS Team Avatar Row with Hover Spread

An overlapped row that fans open when you point at it, so a tight facepile becomes a legible team list without a click. Every avatar moves with translate — never margin — so the fan costs nothing in layout, each face carries a name tooltip, and :focus-within means a keyboard user gets exactly the same reveal as a mouse user.

Published

CSS Avatar List with Name and Role — preview
13 / 22Pure CSS

CSS Avatar List with Name and Role

The member directory every settings page, admin panel and team page needs: avatar, name, role, presence and a row action, aligned on a real grid so long names and short names produce identical columns. Two densities are switchable in CSS, the whole row is one hit target with a single focusable control, and every status carries text as well as colour.

Published

CSS Initials Avatar with Generated Background — preview
14 / 22Pure CSS

CSS Initials Avatar with Generated Background

The no-photo avatar that still looks designed: the app passes a single number — a hue derived from the user's id — and CSS builds the whole swatch from it. Because oklch() pins lightness and lets only hue vary, every generated background is contrast-safe by construction rather than by luck, and three fills (soft, solid, ringed) all read from the same one variable.

Published

CSS Avatar Fallback for Broken Images — preview
15 / 22Light JS

CSS Avatar Fallback for Broken Images

What happens when the photo 404s — and this demo actually breaks one so you can see the fallback fire. The initials layer sits beneath the image from the start, so there is no flash and no layout shift; the image simply stops covering it. Includes the detail almost every tutorial misses: images that already failed before your script ran, caught with a complete && naturalWidth === 0 check.

Published

CSS Letter Avatar Color Palette Set — preview
16 / 22Pure CSS

CSS Letter Avatar Color Palette Set

A complete A-Z colour system for letter avatars, built from one formula instead of 26 hand-picked hex values: the letter's alphabet index becomes a hue, and oklch() holds lightness and chroma fixed so every one of the 26 swatches passes WCAG AA against its own text. Twelve letters are shown as the working proof, with a live contrast toggle that switches between tinted and saturated fills.

Published

CSS Avatar with Hover Profile Card — preview
17 / 22Light JS

CSS Avatar with Hover Profile Card

The hovercard, built so keyboard users are not second-class: the trigger is a real &lt;button&gt;, the card opens on hover and on focus, closes on <kbd>Escape</kbd>, and a 120ms hover-intent delay stops it flickering as the pointer crosses a facepile. CSS anchor positioning pins the card to the avatar where supported, with a plain absolute fallback everywhere else — and the card holds exactly what a hovercard should: name, role, timezone, local time and one action.

Published

CSS Avatar Upload with Hover Overlay — preview
18 / 22Light JS

CSS Avatar Upload with Hover Overlay

The affordance, not the flow: hovering (or focusing) the avatar reveals a camera-icon scrim that says the photo is changeable. The control is a real &lt;input type="file"&gt; wrapped in its &lt;label&gt; — so it is keyboard reachable, announced properly and needs no click handler — and a local preview swaps in immediately with a polite live-region confirmation. No progress bars, no drop zones; this demo is about making "you can change this" legible.

Published

CSS Avatar Picker Grid — preview
19 / 22Pure CSS

CSS Avatar Picker Grid

Choose-your-avatar, done with real form controls: eight options as a radio group, so arrow keys move between them, <kbd>Space</kbd> selects, and the browser handles the roving focus for free. The :checked state paints a ring plus a tick badge — two signals, not just colour — and a live preview at the top updates through :has(). Entirely CSS; the only thing a real app adds is reading .value on submit.

Published

CSS Skeleton Loading Avatar — preview
20 / 22Light JS

CSS Skeleton Loading Avatar

A shimmer placeholder in the avatar's exact shape that crossfades into the real photo the moment it decodes — no layout shift, because the frame owns the geometry and the image only changes opacity. The shimmer animates background-position on a fixed gradient (one property, no repaint of the layout), the loading state is announced with aria-busy, and reduced-motion gets a calm static placeholder instead of a moving one.

Published

CSS Avatar Size Scale System — preview
21 / 22Light JS

CSS Avatar Size Scale System

The design-system demo: five named sizes — xs, sm, md, lg, xl — all derived from a single --size token, with the ring, the status dot, the count badge and the initials type all scaling proportionally because every one of them is expressed relative to that token. A slider retunes the base at runtime so you can watch the whole system stay in proportion instead of drifting.

Published

CSS Comment Thread Avatar Layout — preview
22 / 22Pure CSS

CSS Comment Thread Avatar Layout

The avatar doing its real job: a threaded discussion where every reply aligns to its parent's text column, indent rails make depth legible without guessing, and avatars shrink one step per level so the hierarchy reads at a glance. Built on nested lists with a grid template per comment — so the layout survives long names, missing photos and three levels of nesting without a single absolute position.

Published

FAQ

Frequently asked questions

How do I make a circular avatar in CSS?
Three declarations do the work: border-radius: 50%, aspect-ratio: 1 and object-fit: cover. The last one is the part people skip, and it is what stops a non-square photo from stretching — cover crops the overflow instead of distorting the face. Set the size once with a custom property (--size: 3rem) applied to both inline-size and block-size, or lean on aspect-ratio: 1 and set only the width, which keeps the two from drifting apart when someone edits one and forgets the other. Add object-position: center top when your source photos are portraits, because faces usually sit in the upper third and a centre crop can cut foreheads. Always use a real img element rather than a background image: a background cannot carry alt text, so screen-reader users lose the person's name entirely.
What is the difference between a border and a box-shadow ring on an avatar?
A border participates in layout; a box-shadow does not. Add a 3px border to a 48px avatar and, under the default content-box sizing, the element becomes 54px and every neighbour shifts — which is why avatar rows jump when a ring appears on hover or on an active state. box-shadow: 0 0 0 3px currentColor paints the identical ring with zero layout cost, so rows stay stable and you can animate the spread freely. It also stacks: two shadows give you the gap ring (a page-coloured inner shadow, then the accent outer) that Instagram and Slack both use, which is fiddly with borders. Use outline with outline-offset as a third option, but reserve it for focus states so you do not fight the focus ring. Borders remain the right call when you genuinely want the ring to occupy space, such as a chunky frame that is part of the layout.
How do I build a stacked avatar group with overlap?
Flexbox plus a negative inline margin on every item after the first. Set display: flex on the list, then margin-inline-start: -0.75rem on li + li — a value of roughly a third of the avatar size reads as a deliberate stack rather than a collision. Give each avatar a ring in the page background colour so neighbours separate visually where they overlap; without that ring the faces blur into one shape. Stacking order matters more than people expect: the natural order puts later items on top, which looks wrong because the stack appears to run backwards. Fix it with flex-direction: row-reverse plus reversed margins, or by assigning descending z-index values. For the overflow counter, make the +12 chip the last item with exactly the same dimensions and ring as a real avatar, and expose the full count to assistive tech — aria-label="and 12 more team members" — since a bare plus sign means nothing when read aloud.
What should the alt text be on an avatar image?
It depends entirely on whether the person's name already appears nearby. If the avatar sits alone — a bare facepile, an account-menu trigger — the alt text carries the name: alt="Priya Sharma". If the name is right beside the image as visible text, or already on the link's aria-label, then the image is decorative and alt="" is correct, because otherwise a screen reader announces the name twice in a row. Never write alt="avatar" or alt="profile picture"; that tells a user nothing they could not infer and adds noise. Do not put the status in the alt either — an online dot is separate information and needs its own text equivalent, usually a visually hidden span reading "online", so that presence is not conveyed by a coloured dot alone. This collection follows exactly that split, which is why some demos ship names in alt and others deliberately ship empty alt.
How do I show initials when a user has no profile photo?
Render the initials as real text in the same box the image would occupy, then let CSS pick the background. The most maintainable version has the server or component set one custom property — style="--hue: 217" — and the CSS builds the fill from it with background: oklch(65% 0.13 var(--hue)). Deriving the hue from a hash of the user's name gives every person a stable colour that survives reloads. Centre the letters with grid, and size them relative to the avatar (font-size: 40%) so initials scale with the container instead of needing a value per size. The trap is contrast: a generated palette will eventually produce a light fill under white text and fail WCAG AA. Working in oklch() helps because lightness is perceptually uniform, so pinning L to a fixed value keeps every hue at a predictable contrast against the same text colour.
How do I handle a broken avatar image URL?
Layer the fallback underneath and let the broken image reveal it. Put an initials block in the container, position the img above it, and when the image fails the layer beneath simply shows through — no JavaScript required if you accept the browser's broken-image icon being hidden by the img's own background. For a fully clean result, one line of JS is the pragmatic answer: onerror sets a data attribute or removes the image, and CSS handles the rest. With :has() you can now style the wrapper based on the image state without any script at all in browsers that support it. Whichever route you take, make sure the fallback carries the same accessible name as the image would have, or the user goes from hearing a name to hearing nothing. Demo 15 in this collection deliberately points at a dead URL so you can watch the fallback fire rather than take it on trust.
Are CSS avatars accessible?
They can be, and the failure modes are consistent enough to check in a minute. Use a real img with considered alt text, never a background image, so the name reaches assistive tech. Never convey status by colour alone — an online dot needs a shape difference, an icon, or visually hidden text, because a red-green distinction is invisible to a large share of users. Expose counts as numbers: a badge showing 99+ should carry aria-label="127 unread notifications" so the real figure is available. Interactive avatars must be real button or a elements with a visible focus ring and a 44×44px minimum target per WCAG 2.5.8, which often means padding around a smaller visual avatar. Hover-only profile cards are the most common trap in this space: if the card appears on hover it must also appear on keyboard focus, or the content is unreachable without a mouse.
How do these avatars port to React, Vue, Svelte and Tailwind?
The CSS ports unchanged — every .av-NN selector and custom property is framework-agnostic, and 16 of the 22 designs use no JavaScript at all. The natural component boundary is a single Avatar that accepts size, shape, status and a fallback, with the size scale from demo 21 as its prop contract: one --size property drives the ring, badge and status dot together, so a consumer sets size="lg" and everything scales in proportion. Group components then compose that Avatar rather than restyling it. For Tailwind, the shapes and rings map to rounded-full and ring-2 ring-white directly; the generated-hue trick needs an arbitrary value or a CSS variable set inline, since the palette is per-user data rather than a design token. The six JavaScript demos are small init functions that port to useEffect with a cleanup return, onMounted with onBeforeUnmount, or Svelte's onMount.

Related collections

15 CSS 3D Tilt Hover Cards preview

15 CSS 3D Tilt Hover Cards

15 mouse-aware 3D tilt hover cards — e-commerce product spotlight, glassmorphism parallax team card, interactive pricing tier, holographic NFT collectible, pop-out mascot, dark tech grid with border glow, media player album art, blog article preview, cyberpunk neon glow, dashboard KPI widget, minimalist real estate, flip-to-back tilt, mobile app showcase, course learning card, and a Pure CSS touch-friendly tilt. Vanilla JS writes --rx/--ry/--mx/--my; all rendering stays in CSS on the GPU.

24 CSS Animated Cards preview

24 CSS Animated Cards

24 hand-coded CSS animated card patterns organised by what triggers the motion, not by card style. Scroll and entrance triggers: staggered grid reveals, @starting-style mount-in, scroll-driven scale and fade on animation-timeline: view(), View Transitions API card-to-detail morphs, blur-to-sharp lazy image loading, and FLIP re-layout when a filter changes. State-change triggers: add-to-cart success morph, like and save particle burst, expand and collapse to intrinsic height with calc-size(), swipe-to-dismiss on Pointer Events, and skeleton-to-loaded crossfade. Data-driven triggers: count-up KPI metrics, SVG sparkline draw-on-enter, and progress ring fill on load. Ambient idle loops: breathing glow, floating drift, animated gradient mesh backgrounds, conic rotating borders, auto-cycling testimonial decks, and live status pulses. Plus four hover patterns where the effect is the topic itself: cursor spotlight, holographic foil glare, corner ribbon slide, and horizontal accordion expand. Every card is scoped under a .ac-NN prefix for no-collision pasting, guards prefers-reduced-motion, animates compositor-only properties, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.

25 CSS Button Groups preview

25 CSS Button Groups

25 hand-coded CSS button groups: segmented controls, split buttons, pill radios, toggle groups, filter chips, floating action buttons, pricing toggles, Web3 wallet-connect grids, AI model pickers, icon toolbars — with Popover API, offset-path, View Transitions, @property, :has(), and every modern CSS primitive. Zero dependencies vs Radix/shadcn/Aceternity, WCAG 2.2 AA accessible, MIT licensed.

Search CodeFronts

Loading…