Card Vanish
On removal, the card breaks into 24 tiles that each fly off toward a random point, in a diagonal wave from the top left corner (0.8 s); on return, the tiles come back and the card rebuilds with a bounce (0.6 s). Divs and CSS keyframes, no canvas: 2.4 KB of JavaScript, a plain 150 ms fade when the user reduces motion.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Transitions has 52 effects, including 9 free. Explore the category →
3 usage examples



How it works
The .cv-card (160 × 100 px, 14 px corners, #6366f1 → #8b5cf6 gradient) sits in .cv-wrapper, which serves as the tiles' frame of reference; the .cv-root block declares its #0a0a0f background and places the button below. A click on .cv-btn alternates both directions: dissolve, then rebuild. The state reached holds: measured 1.45 s then 3.45 s after the click, the dissolved card stays at opacity 0, and the rebuilt card stays solid until the next click.
To dissolve, the script reads the card's size and creates a 6 × 4 grid of div.cv-particle (26.7 × 25 px for the demo card), each painted with the same gradient. Each tile gets two variables, --tx and --ty, drawn at random between −100 and 100 px, and a 30 ms delay per row and per column: the wave starts from the top left corner and reaches the opposite one 240 ms later. The cvDissolve animation (0.8 s, cubic-bezier(.25, .46, .45, .94)) takes them to translate(var(--tx), var(--ty)) scale(0) while fading them out. Meanwhile, the card goes to opacity 0 and scale 0.95 in 0.3 s, then becomes visibility: hidden at the end of the fade. The tiles are removed from the DOM after one second.
The return takes the reverse path: 24 new tiles start from random points and reach their cell in 0.6 s (cvMaterialize), while the card comes back with cvCardIn, from scale 0.8 to 1 on an overshooting curve (cubic-bezier(.34, 1.56, .64, 1)). The card therefore reappears before the tiles have finished converging — measured at opacity 0.8 after 150 ms — and the tiles land on it. The script walks every .cv-root on the page: several cards live side by side, each with its own state. The tiles carry the card's color, not its content: the text fades with the card, the dust is made of gradient pieces.
Accessibility
- Reduced motion: under
prefers-reduced-motion, the script creates no tile and the card fades out or back in 150 ms, with no scale change — measured in Chromium and Firefox: 0 tiles, opacity 0.3 at 60 ms, 0 at 460 ms. - Removed card, absent card: at the end of the fade, the card switches to
visibility: hidden; it leaves keyboard navigation and screen readers no longer read it, even if it contains links. The tiles are emptydivs, with no text. - Announce the removal: the button does not say what state the card is in. In real use, change its label after the click ("Restore") or set
aria-pressed, and confirm the action in anaria-livearea ("Booking canceled"). - Contrast: 14.4 px bold white text on the card, 4.47:1 on
#6366f1and 4.2:1 on#8b5cf6, just below the 4.5:1 AA threshold across the gradient; darken both ends (#4f46e5→#7c3aed, 6.29:1 and 5.7:1) if the card carries important text.
Browser compatibility
CSS keyframes with variables (var(--tx) inside @keyframes), transitions and about fifty lines of JavaScript, no dependency, no canvas. Measured in Chromium 151, Firefox 153 and WebKit 26: 24 tiles, same diagonal wave, card at opacity 0 after dissolving and solid after rebuilding, no tiles under reduced motion. The script uses NodeList.forEach, available since Chrome 51, Firefox 50 and Safari 10.
Without JavaScript, the card stays displayed and the button does nothing. With reduced motion, the card disappears and returns with a 150 ms fade, without tiles.
The code
HTML structure to paste into your page (the CSS + JS come with Premium):
<div class="cv-root">
<div class="cv-wrapper">
<div class="cv-card">Card Content</div>
<!-- 24 div.cv-particle added by the script for the animation -->
</div>
<button class="cv-btn" type="button">Toggle Card</button>
</div>
The full HTML + CSS + JS of Card Vanish, ready to paste — plus all 840 effects. Or $299 once, lifetime access.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Tile grid (JS — cols = 6, rows = 4) |
6 × 4 = 24 tiles | More tiles give finer dust: 10 × 6 = 60 tiles stay smooth. Beyond 150, the browser animates many elements at once; keep tiles at least 10 px wide. |
Spread (JS — * 200) |
±100 px on each axis | * 400 throws the tiles twice as far, outside the card; for a fall, replace ty with 60 + Math.random() * 120 (always downward). |
Wave (JS — (r + c) * 0.03) |
30 ms per row, 240 ms corner to corner | (rows - 1 - r + c) * 0.03 starts the wave from the bottom left corner; Math.random() * 0.3 gives a directionless scatter. |
Durations (CSS — cvDissolve, cvMaterialize) |
0.8 s and 0.6 s | With the original 0.8 s, the last tiles end their run at 1.04 s and the script removes them at 1 s, at 95% of the way, already almost invisible. If you lengthen the dissolve, lengthen the tile removal by as much (1000 in the script), or they vanish mid-run. |
Tile color (JS — particle.style.background) |
linear-gradient(135deg, #6366f1, #8b5cf6) |
It is written in the script, apart from the card: change both together. To pick up the card's color automatically, write getComputedStyle(card).backgroundImage. |
Depth (CSS — .cv-wrapper perspective: 800px) |
declared, no visible effect | No animation rotates in 3D, so the perspective changes nothing. Add rotateX(60deg) in the last step of cvDissolve to make the tiles tip over as they fly off. |
FAQ
div painted with the card's gradient, not a piece of its image. The text fades with the card in 0.3 s while the colored tiles fly off; the eye reads a card coming apart. Cutting up the real rendering would require copying the card into a canvas (html2canvas or similar), heavier and fragile with fonts and cross-origin images.card.classList.add('cv-vanishing'), add setTimeout(function () { wrapper.remove(); }, 1000);: the dust has finished falling after one second. In a list, remove the parent list item instead, and do it after your server responds if the removal can fail.