Avatar Morph
An 80 px round avatar that stretches into a 220 × 120 px card: the circle becomes a rounded rectangle, the initials slide to the left, then the name, role and a badge appear a quarter second later. The category's only circle-to-card change, in pure CSS without a line of JavaScript; it opens on hover, from the keyboard and on touch, and changes shape without stretching when the user reduces motion.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Liquid has 31 effects, including 6 free. Explore the category →
3 usage examples



How it works
The .avatar-morph block (80 × 80 px) holds a .avatar-morph-inner frame rounded at 50%, the .avatar-pic initials dot (60 px, violet-pink gradient) and a transparent .avatar-info block: name, role, badge. On hover, the block grows to 220 × 120 px and the frame to 16 px corners, with transition: .6s cubic-bezier(.68, -.3, .27, 1.2): a slight back-up at the start, a slight overshoot at the end. The dot shrinks to 50 px and slides to the left edge, vertically centered (top: 50% and translateY(-50%)). The text, set 80 px from the edge, fades in over 0.4 s after a 0.25 s wait: it only shows once the card has room for it.
The dot starts from a position written in pixels (left: 9px; top: 9px, the center of the circle) rather than the automatic position of a centered element: an auto value does not interpolate, so the dot would jump down at once before moving back up. Measured frame by frame in Chromium 151, Firefox 153 and WebKit 26: the top of the dot glides from 10 to 35 px over the 0.6 s, a different value on every frame, with no jump.
Every :hover rule is paired with a :focus-within rule, and the block has tabindex="0": the card also opens when reached with Tab, and under a finger, since touching the element gives it focus. The keyboard focus ring (2 px violet) sits on the inner frame, following its rounding. The card's text is always in the page, just transparent: a screen reader reads it whether the card is open or closed.
Accessibility
- Keyboard: measured in all three engines, WebKit included, Tab reaches the avatar and the card opens; it closes when focus moves on. The focus ring only shows for keyboard users (
:focus-visible). - Touch: measured with mobile emulation, a tap opens the card in Chromium and in WebKit. In Chromium, tapping elsewhere closes it; in WebKit, it stays open until another element takes focus (link, button, another avatar). To close it on a tap anywhere, add:
document.addEventListener('pointerdown', function (e) { if (!e.target.closest('.avatar-morph')) document.activeElement.blur(); }); - Screen readers: the initials dot is hidden (
aria-hidden); the name, role and badge are read in order, open or not. If the avatar leads to a profile, put a real link around the name. - Reduced motion: under
prefers-reduced-motion: reduce, the circle becomes a card at once (measured: the final shape is there at the first measure), and only the text fades in.
Browser compatibility
Pure CSS (transitions, :hover, :focus-within), 3.3 KB, no JavaScript. Measured in Chromium 151, Firefox 153 and WebKit 26: same stretch, same sliding initials, same keyboard opening, same stop under reduced motion. :focus-within exists since Chrome 60, Firefox 52 and Safari 10.1.
Without :focus-within, the card only opens on mouse hover; the text stays readable by screen readers. Without transitions, the circle becomes a card at once.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0409-root">
<div class="avatar-morph" tabindex="0">
<div class="avatar-morph-inner">
<div class="avatar-pic" aria-hidden="true">JD</div>
<div class="avatar-info">
<div class="avatar-info-name">…</div>
<div class="avatar-info-role">…</div>
<span class="avatar-info-badge">…</span>
</div>
</div>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Sizes (CSS — width / height of .avatar-morph and its :hover rules) |
80 px diameter, 220 × 120 px card | The text starts 80 px from the edge (left of .avatar-info) and does not wrap: for a longer role, widen the card (260 px) rather than shrinking the font. |
Bounce (CSS — transition: .6s cubic-bezier(.68, -.3, .27, 1.2), three times) |
0.6 s, slight back-up then slight overshoot | .4s ease-out gives a crisper opening. Keep the same value on the block, the frame and the dot so they move together. |
Text delay (CSS — transition-delay: .25s on .avatar-info) |
0.25 s | Below 0.15 s, the text appears while the card is still narrow and gets cut off; beyond 0.4 s, the card looks empty for a moment. |
Colors (CSS — .avatar-morph-inner, .avatar-pic, .avatar-info-badge) |
violet #a855f7, pink #ec4899, cyan at 15% |
If the card opens over other elements, add a solid color under the translucent gradient (background: linear-gradient(…), #121f3f) so the neighbors do not show through. |
Badge (HTML — .avatar-info-badge) |
"Online" | A short, useful status: "On duty", "On the airfield", "Away until the 12th". Remove it if you have none, the card stays balanced with two lines. |
FAQ
left and top: on hover, it would jump straight to top: 50%, at the bottom of the circle, then move back up with the translation. Writing the center position in pixels (80 − 2 of border − 60, divided by two) gives the browser a starting point; measured, the dot glides from 10 to 35 px without a jolt.tabindex="0" makes the avatar focusable, and a tap gives it focus, which triggers the :focus-within rules. Measured with mobile emulation in Chromium and WebKit. The difference is in closing: Chromium closes on a tap elsewhere, WebKit waits for focus to move to another interactive element; the line of JavaScript in the accessibility section makes both behave the same.