Hover Lift
Card lifts 15 px and scales up 2% on hover — CSS cubic-bezier easeOutBack with drop shadow and indigo glow ring.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Cards has 41 effects, including 6 free. Explore the category →
3 usage examples



How it works
The effect is built on a single transition: .4s cubic-bezier(.175, .885, .32, 1.275) rule on .card-lift. The fourth parameter 1.275 exceeds 1, producing an overshoot: the card rises slightly past its final position then settles back, mimicking an elastic spring (easeOutBack). The 0.4 s duration is long enough to be noticed yet short enough to feel snappy.
On hover, .card-lift:hover applies transform: translateY(-15px) scale(1.02) — a 15 px upward lift and a 2% scale increase. Both transforms run on the GPU compositor thread with zero layout reflow, guaranteeing 60 fps even on budget devices. The transition reverses automatically when the pointer leaves, with no extra code.
Two box-shadow layers are added simultaneously: a large diffuse shadow (0 20px 40px rgba(0,0,0,0.3)) simulates the card casting a shadow on the surface below, reinforcing the illusion of height; a 1 px spread-only ring (0 0 0 1px rgba(99,102,241,0.3)) adds a subtle indigo glow (#6366f1) to focus attention on the active card. The entire effect is 100% CSS, zero JavaScript.
Accessibility
- prefers-reduced-motion missing: the code contains no
@media (prefers-reduced-motion: reduce)block. The 0.4 s transition runs even when the user has enabled that OS preference. Recommended fix:@media (prefers-reduced-motion: reduce) { .card-lift { transition: none; } }. - The reference
.card-demois a non-interactive<div>— not keyboard-focusable. If the card is clickable, use a native<button>or<a>so it is focusable and announced correctly by screen readers. - No
:focus-visiblestyle is defined in the code: the hover effect is not reproducible via keyboard. Add.card-lift:focus-visible { transform: translateY(-15px) scale(1.02); box-shadow: … }to match the hover state for keyboard users. - On mobile (touch),
:hoverstays sticky after a tap and resets on the next — no immediate feedback on first touch. Add atouchstartJS listener if tactile responsiveness is required. - Default text contrast: white
#fffon background#12121a— ratio ≥ 15:1, well above WCAG AAA (7:1 threshold).
Browser compatibility
Relies solely on CSS transitions and GPU transforms — natively supported in all modern browsers since 2016. Zero external dependencies.
Without CSS transition support (very old browsers), the card displays normally on hover with no animation — no errors, the UI remains fully readable.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<!-- .card-demo and .card-lift are required — inner content is free -->
<div class="card-demo card-lift">
<img class="card-thumb" src="thumbnail.jpg" alt="Thumbnail">
<div class="card-body">
<span class="card-tag">Category</span>
<h3 class="card-title">Card title</h3>
<p class="card-desc">Short content description.</p>
<button class="card-cta">Read →</button>
</div>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| --bg-card | #12121a | Card background color — swap for your brand color. Redefine on :root or directly on the .card-demo selector. |
| --radius-xl | 1rem | Corner border radius. 0 = square card, 1.5rem = pronounced rounding. The value flows through var(--radius-xl) in border-radius. |
| --border | rgba(255,255,255,0.08) | Color and opacity of the visible resting border. Increase opacity (0.18–0.25) for a crisper edge on dark backgrounds. |
| transition (.card-lift) | .4s cubic-bezier(.175,.885,.32,1.275) | Duration and easing for the whole animation. Shorten to .2s for snappier feedback, or switch to ease-out to remove the overshoot bounce. |
| translateY (.card-lift:hover) | -15px | Lift height. -8px = subtle (small cards), -20px = dramatic (tall cards). Scale up proportionally with card height. |
| scale (.card-lift:hover) | 1.02 | Zoom factor on hover. 1.0 = pure lift without zoom, 1.05 = more pronounced zoom. Keep below 1.06 to avoid clipping neighboring cards. |
| ring color (.card-lift:hover) | rgba(99,102,241,.3) | Color of the 1 px glow ring (indigo #6366f1). Swap for your primary brand color, or set to rgba(0,0,0,0) to remove the ring and keep only the shadow. |
FAQ
.card-demo and .card-lift classes to your card component; no directives or lifecycle hooks are needed.:hover sticks after the first tap and resets on the next. For immediate tactile feedback, add a JS listener: card.addEventListener('touchstart', () => card.classList.add('is-lifted')) and define .card-lift.is-lifted with the same rules as :hover. Remove the class on touchend.translateY proportionally: -20px to -24px works well for tall cards. Also increase the drop shadow (0 30px 60px rgba(0,0,0,0.35)) to maintain the illusion of height. The scale(1.02) value adapts automatically to the card's dimensions without any change.