Buttons✨ Premium

Press Feedback

Orange button with a tinted shadow: it lifts 2 px on hover, then on press drops 2 px, squashes to 95% and its content to 98% while the shadow tightens — 150 ms, pure CSS.

CSSActiveMicro

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. Buttons has 27 effects, including 2 free. Explore the category →

3 usage examples

Add — dish card in a food delivery app — Press Feedback example 1

① Add — dish card in a food delivery app

WhenDish list: photo, name, price and one add-to-cart button per card.
WhyThis button gets pressed dozens of times per order, often with a thumb: the 150 ms squash confirms each addition with no waiting animation. Orange is the color of fast food; darken it for contrast.
SettingsCompact button (padding: 10px 16px, 13.5 px), #c2410c → #9a3412 gradient, touch-action: manipulation, shadow reduced to 0 3px 10px.
Pay — sticky action bar of a mobile checkout — Press Feedback example 2

② Pay — sticky action bar of a mobile checkout

WhenBar pinned to the bottom of the screen: total on the left, full-width pay button on the right.
WhyOn mobile there is no hover: only the press counts, and that is precisely what this effect makes visible. The flex span.btn-content takes the amount and a lock icon with the 8 px gap.
SettingsFull-width button, padding: 15px 20px, 🔒 icon with aria-hidden inside .btn-content, 0 6px 20px shadow, scale(.97) on press for a large button.
Publish — toolbar of a content editor — Press Feedback example 3

③ Publish — toolbar of a content editor

WhenHeader of an editor (article, product, page): draft status, a secondary button, the publish button.
WhyPublishing is the screen's irreversible action; the squash gives the click physical weight and the tinted shadow sets this button apart from neutral actions. The hover lift stays discreet in a dense bar.
Settingspadding: 11px 20px, 14 px, ↑ icon inside .btn-content, translateY(-1px) hover, dark gradient for contrast.

How it works

Three states on .btn-press-feedback, a linear-gradient(135deg, #f97316, #ea580c) with a tinted shadow 0 4px 15px rgba(249,115,22,.4) — that orange shadow, rather than a grey one, is what makes the button seem to radiate onto its surface. transition: .15s (all properties, ease curve) links the states.

On :hover: transform: translateY(-2px) and a farther, wider shadow, 0 8px 25px rgba(249,115,22,.5). The button seems to move away from the surface. On :active: translateY(2px) scale(.95) and a flat shadow 0 2px 8px rgba(249,115,22,.3) — it drops below its resting position, shrinks and the shadow hugs it. Measured in Chromium: 134 × 50 px at rest, 128 × 47.5 px during the press, shifted 2 px down.

The label is wrapped in <span class="btn-content">, set to display: flex; align-items: center; gap: 8px — ready to take an icon next to the text — with its own transition: transform .15s. On press, .btn-press-feedback:active .btn-content { transform: scale(.98) }: the content squashes on top of the button, i.e. 0.95 × 0.98 ≈ 0.93 for the text. This double squash makes the label look pushed into the button, not merely shrunk with it.

Everything goes through transform and box-shadow: no layout property changes, neighbors don't move (unlike 3D Press, which relies on a border). The span.btn-content is needed for the inner squash and the icon spacing; without it, the button works but loses those two details.

Accessibility

  • Insufficient contrast as shipped: white text on the #f97316 → #ea580c gradient = 2.8:1 and 3.6:1, below the 4.5:1 AA threshold for 16 px text. Switch to linear-gradient(135deg, #c2410c, #9a3412) (5.2:1 and 7.3:1), or keep #ea580c alone with an 18 px bold label (3:1 threshold). Recolor the shadow along with it (rgba(194,65,12,.4)).
  • prefers-reduced-motion not handled: the movements are 2 to 4 px over 150 ms. Add @media (prefers-reduced-motion: reduce) { .btn-press-feedback, .btn-press-feedback .btn-content { transition: none } } — the states switch without gliding.
  • Keyboard: :active applies while Space is held, so the squash works on the keyboard. The hover lift has no equivalent: add .btn-press-feedback:focus-visible { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(249,115,22,.5) }. The native outline is preserved, but blue on orange reads poorly — outline: 2px solid #fff; outline-offset: 3px is crisper.
  • Touch: one of the few effects in the catalog designed for the finger — :active fires on touch and the squash is visible under the thumb during the tap. Add touch-action: manipulation to remove the double-tap delay on iOS. The :hover state sticks after the tap (@media (hover: hover)). Target ≈ 50 px tall, above the 44 px minimum.
  • Screen readers: the span.btn-content is a plain container, the accessible name remains the label. If you place an icon inside, set it to aria-hidden="true" so it isn't read.

Browser compatibility

Requires CSS transitions on transform and box-shadow, plus display: flex for the content — every browser since 2012. No JavaScript, zero dependencies.

Chrome 29+✓ Full
Firefox 28+✓ Full
Safari 9+✓ Full
Edge 12+✓ Full
Mobile iOS✓ Full (:hover sticks after a tap)
Android Chrome✓ Full

Without transitions, the three states apply instantly: the button jumps 2 px and squashes at once, the shadow changes with no fade — the press feedback stays readable.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
transform (CSS — :active) translateY(2px) scale(.95) Push-in on press. scale(.97) for a large button (5% of 300 px = 15 px, too visible); translateY(3px) for a franker travel.
transform (CSS — :active .btn-content) scale(.98) Extra squash of the content (text + icon). 1 cancels it; .94 clearly sinks the text into the button.
transform / box-shadow (CSS — :hover) translateY(-2px) / 0 8px 25px .5 Hover lift. Remove the rule to keep only the press (the mobile behavior); translateY(-1px) in a tight toolbar.
Shadow color rgba(249,115,22,…) (CSS — 3 occurrences) orange at .4 / .5 / .3 The shadow is tinted with the button's color: that's what makes it “radiate”. A grey (rgba(0,0,0,.3)) gives a classic shadow; match the hue if you change the gradient.
transition (CSS — .btn-press-feedback and .btn-content) .15s Duration of all three transitions. .1s = crisper click; .25s = softer, but the feedback then lags behind the finger.
background (CSS — .btn-press-feedback) linear-gradient(135deg, #f97316, #ea580c) Button color. For AA contrast with white text: #c2410c → #9a3412. Recolor the shadow along with it.
gap (CSS — .btn-content) 8px Space between the label and an icon placed inside the span. Without an icon, the value has no effect.

FAQ

The two don't add up the same way: the button goes to 95%, shadow and corners included; the content goes to 98% of that already-reduced button, i.e. ≈ 93% of its resting size. So the text shrinks slightly more than the box around it, which reads as a push-in — as if the label were moving away from the eye. Without the second rule, the button merely looks like it's getting smaller.
Not for the button's motion, yes for two details: the inner squash (:active .btn-content matches nothing without it) and the icon spacing (gap: 8px). A bare <button class="btn-press-feedback">Send</button> lifts and sinks normally. If you add an SVG icon, place it inside the span with aria-hidden="true"; align-items: center aligns it with the text.
The effect already works on touch: :active applies during the tap. Two additions: touch-action: manipulation on the button to remove the double-tap detection delay (iOS Safari), and, where the context warrants it, a very short vibration on click via navigator.vibrate(8) (Android only, iOS doesn't expose it). Avoid durations above 150 ms: the finger has already left.