Liquid✨ Premium

Card Morph

A compact card (avatar dot, name, role) that widens from 200 to 300 px with a bounce on click and rolls out a paragraph and three gradient figures; a second click folds it back. The content shows up inside the same card, without leaving the page: the header is a real button that says whether the card is open, and folded details are hidden from screen readers.

CSSJSLayout

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

Grape variety card — the "Our vines" page of a wine estate — Card Morph example 1

① Grape variety card — the "Our vines" page of a wine estate

WhenFolded, the card shows the "CF" dot and "Cabernet franc — Les Perrières plot"; unfolded, the description of the soil and three figures: 2.4 hectares, 45-year-old vines, 38 hl/ha.
WhyThe three figures at the bottom of the unfolded card are built into the code: the curious open it, the others just read the name.
SettingsBurgundy and gold tones: card background rgba(190,24,93,.22) → rgba(234,179,8,.08), dot #9f1239 → #e11d48, figures in a #fbbf24 → #f472b6 gradient; card set at the top left so it opens to the right and downward.
Craft fair exhibitor — the profile of a knifemaker — Card Morph example 2

② Craft fair exhibitor — the profile of a knifemaker

WhenFolded: "Yann Le Goff — knifemaker, booth B12"; unfolded: his introduction and "18 years forging, 6 steels, 2 demos a day", next to the aisle map.
WhyThe card grows in place within the exhibitor list: you keep your spot in the list instead of opening another page.
SettingsCopper tones: background rgba(234,88,12,.18), dot #78350f → #ea580c, figures #fdba74 → #e7e5e4; two-line paragraph to stay under the 200 px max-height.
This week's grower — a CSA farm-share page — Card Morph example 3

③ This week's grower — a CSA farm-share page

WhenFolded: "Bois-Joli Farm — vegetables"; unfolded: a word from the grower and "14 km, 3 ha, organic since 2011", above the contents of Thursday's basket.
WhyThe basket lists several growers: each card stays small until clicked, and the page stays short.
SettingsGreen tones: background rgba(101,163,13,.2), dot #3f6212 → #84cc16, figures #bef264 → #fde047; the other growers as compact cards in the right column.

How it works

The .card-morph card is 200 px wide, with 20 px of padding, a translucent violet background and 16 px corners. Its .card-header header is a <button> holding the 40 px avatar dot (initials on a violet-pink gradient), the name and the role. Below, .card-details waits folded: max-height: 0, opacity: 0. On click, the script toggles .expanded on the card: it goes to 300 px with transition: .6s cubic-bezier(.68, -.55, .27, 1.55), a bounce that makes it shrink slightly and then overshoot its width; the details open (max-height up to 200 px over 0.6 s, opacity and margin over 0.4 s).

The whole card listens for clicks, but only the header is a button. That is deliberate: a button wrapping the paragraph and the figures would read all that text as its name. From the keyboard, Tab reaches the header, Enter or Space fires a click that bubbles up to the card, and aria-expanded switches to true or false. When folded, the details are also made invisible (visibility: hidden, applied 0.6 s after closing starts so the animation is not cut): a screen reader does not read text hidden on screen.

The three figures are painted in a violet-cyan gradient through background-clip: text (with its -webkit- form) and -webkit-text-fill-color: transparent. The height runs through max-height, because an auto height does not animate everywhere: 200 px leave room for a paragraph of three or four lines and the row of figures; longer content would be cut off, so raise the value. The ten-line script walks through every .fx-0406-root .card-morph: several cards live side by side, each with its own state.

Accessibility

  • Keyboard: measured in Chromium 151 and Firefox 153, Tab reaches the header, Enter or Space opens then closes the card, and aria-expanded follows. The focus ring (2 px violet, 4 px offset) stays inside the card's padding. In Safari, Tab only stops on buttons if the keyboard setting asks for it (or with Option+Tab).
  • Screen readers: the header is announced as "Alice Laurent UI/UX Designer, button, collapsed"; the initials dot is hidden (aria-hidden). When folded, the paragraph and figures are not read.
  • Reduced motion: under prefers-reduced-motion: reduce, the card takes its 300 px at once, without bounce, and the details fade in over 0.3 s. Measured: no frame changes after 300 ms.
  • Contrast: the paragraph is white at 60% on a dark background (about 7:1); the figure captions, white at 40%, drop to about 4:1. Keep them short, or raise their opacity if your background is lighter.

Browser compatibility

CSS (transitions on width, max-height, opacity; background-clip: text) + 0.5 KB of JavaScript, no dependencies. Measured frame by frame in Chromium 151, Firefox 153 and WebKit 26: same bouncy widening, same unfolding details, same stop under reduced motion. The card's gradient background does not animate: it switches at once, under the width that does glide.

Chrome 60+✓ Full
Firefox 60+✓ Full
Safari 12+✓ Full (Tab depends on the keyboard setting)
Edge 79+✓ Full
Mobile iOS 12+✓ Full (touch)
Android Chrome 60+✓ Full (touch)

Without JavaScript, the card stays folded and its details cannot be reached: if the paragraph and figures matter, link to a full page. Without background-clip: text, the figures show as solid gradients (colored rectangles): use a plain color instead.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0406-root">
  <div class="card-morph-wrapper">
    <div class="card-morph">
      <button type="button" class="card-header" aria-expanded="false">
        <span class="card-avatar" aria-hidden="true">AL</span>
        <span class="card-id"><span class="card-name">…</span><span class="card-role">…</span></span>
      </button>
      <div class="card-details">
        <p>…</p>
        <div class="card-stats">
          <div class="card-stat"><div class="card-stat-value">142</div><div class="card-stat-label">…</div></div> … (3 figures)
        </div>
      </div>
    </div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Widths (CSS — width of .card-morph and .expanded) 200 px folded, 300 px unfolded The gap makes the effect: 220 → 340 px for longer text. On mobile, width: min(300px, 100%) keeps the unfolded card inside the screen.
Maximum height of the details (CSS — max-height of .expanded .card-details) 200 px Raise it if your paragraph runs past four lines (300 px for six lines). Too large a value delays closing: the transition starts from that value, not from the real height.
Bounce (CSS — transition: .6s cubic-bezier(.68, -.55, .27, 1.55)) 0.6 s, back-up then overshoot .4s ease gives an opening without bounce. Keep the same duration as max-height so width and height land together.
Tones (CSS — background of the card, of .card-avatar and of .card-stat-value) violet #a855f7, cyan #06b6d4, pink #ec4899 Match all three to your brand. The unfolded card gets a slightly denser background and a 60 px shadow: keep that difference, it says the card is open.
Content (HTML — .card-details) a paragraph and three figures Put anything there (list, link, button). A link or button inside the details passes its click on to the card: add e.stopPropagation() to its click so it does not fold the card.

FAQ

Because a button takes all its content as its name: a whole card as a button would be announced with the paragraph and figures every time keyboard focus lands on it. The header carries a short name (the name and role), aria-expanded gives the state, and the mouse can still click anywhere on the card, since the card is what listens for the click.
Because a transition from height: 0 to height: auto does not animate in every browser: it jumps. max-height from 0 to 200 px animates everywhere, with one limit: content taller than 200 px is cut off, and closing starts by "using up" the gap between 200 px and the real height. Chrome 129 can animate to auto with interpolate-size: allow-keywords; until Firefox and Safari follow, max-height is the choice that works everywhere.
Avatar Morph starts from an 80 px circle that becomes a card on hover (or focus), in pure CSS, for short information: a name, a role, a badge. Card Morph starts from a card that is already rectangular, opens on click and rolls out real content, a paragraph and figures. Pick Avatar Morph for a row of faces you hover over; Card Morph for a list of profiles you open one by one.