
Scroll Down Arrow Bounce
translateY with a multi-stop bounce keyframe — never margin-top or padding-top which would trigger layout on every frame.Published
16 copy-paste CSS bounce animation templates built as real-world use cases — landing-page scroll-down arrow, animate.css-style bounce-in entrance modal, Stripe payment success checkmark, Sonner/Radix toast notification, chat typing dots (wave), button hover bounce, SaaS pricing card hover lift, Shopify Add-to-Cart cart-icon shake, notification badge pop, dark-mode toggle switch elastic snap, physics ball with squash-and-stretch, weightless floating badge, bouncing letters wave, Stripe checkout form error alert shake, DVD screensaver viewport bounce, and Tailwind animate-bounce customization. Every bounce animates only transform and opacity — never margin-top, top, width, or height, which trigger the layout+paint pipeline every frame and tank INP scores on real mobile hardware. Scoped under .bn-NN for no-collision pasting, prefers-reduced-motion guarded with tier-appropriate fallback, framework-agnostic.
Related30 CSS Keyframe Animations16 CSS Pulse Animations22 CSS Transitions

translateY with a multi-stop bounce keyframe — never margin-top or padding-top which would trigger layout on every frame.Published

bounceIn entrance every animate.css user has copy-pasted at some point, rewritten as vanilla CSS with a modern cubic-bezier + 5-stop keyframe. A single centered card scales in from 0 with elastic overshoot then settles. Perfect drop-in replacement for the animate__bounceIn class most tutorials still teach — no 20KB library import needed. Click the trigger to replay the entrance.Published

stroke-dashoffset. Stripe checkout / Apple Pay / Shopify payment success aesthetic (mint #d1fae5 success surface + emerald #065f46 check). The bounce reads as "you're good." The classic two-stage cascade — circle pops, then check draws — that every well-designed confirmation UI uses.Published

Published

#007aff) on a soft-gray chat surface. The pattern users search for when building chat interfaces, AI streaming responses, or any loading state that needs to feel calm rather than urgent.Published

#f97316) e-commerce CTA color, satisfying tactile feedback the moment users hover. The interaction reads as "press me" without the intrusive infinite pulse of always-on CTAs.Published

Published
Published

Published

<input type="checkbox"> + :checked — no JavaScript needed. The bounce reads as "switch has snapped, state is committed."Published

Published

alternate iteration so the up-and-down motion never resets — smooth continuous drift.Published

animation-delay. Every letter runs the SAME translateY bounce keyframe but starts at a different point in the cycle, creating the wave illusion. Users search for this when building error pages, empty states, or playful hero moments.Published

translateX shake — never a diagonal or scale change.Published

Published

animate-bounce customization reference — default utility, arbitrary-value tweak, and custom keyframes registered in tailwind.config.js. Three side-by-side badges bouncing at different heights and durations show how each tier controls the effect. The Stack Overflow / dev.to search intent "how do I customize Tailwind's animate-bounce" solved with a copy-paste reference. Tailwind teal palette + JetBrains Mono code snippets so users see exactly what to write.Published
transform and opacity (never top, margin, padding, width, or height) so the animation runs on the GPU compositor thread with zero layout cost. Two implementation strategies dominate: (1) cubic-bezier overshoot — a single 2-stop keyframe (0% → 100%) with a timing function like cubic-bezier(.34, 1.56, .64, 1) where the second Y coordinate above 1 creates a peak-and-settle. Simple, works for buttons and modals. (2) Multi-stop keyframe — a 4-6 stop cascade like 0% scale(0) → 40% scale(1.15) → 70% scale(.95) → 100% scale(1). Necessary when you want asymmetric bounce (bigger up, smaller down) or squash-and-stretch physics. Both patterns keep the animation compositor-only, so 20 concurrent bounces run at 60fps even on mid-tier mobile. See Demo #1 (Scroll Down Arrow) for the multi-stop cascade and Demo #2 (Bounce-In Modal) for the 5-stop animate.css-style entrance.margin-top, padding, top, width, or height forces the browser to run its full layout + paint + composite pipeline on every animation frame — 60 times per second. The layout stage is expensive because any size or position change on any element potentially reflows its siblings, its parent, and every descendant. Paint then rebuilds pixel buffers for every affected region. Composite finally uploads to the GPU. On mid-tier mobile (mid-2020s Android, entry iPhones), this pipeline can take 15-20ms per frame — right at the edge of the 16.67ms budget for 60fps. Add one bounce animation using margin-top: 0 → 20px → 0 and you're at 22ms per frame → 45fps. Add three concurrent bounces → 33ms → 30fps → visible stutter. Now measure your INP (Interaction to Next Paint) — it will hit 200ms+ on real hardware, and Google flags this as "Poor" in Core Web Vitals. Your Search Console will show the regression within a week. The compositor-only alternative: transform: translateY and opacity skip layout and paint entirely — they run on the GPU compositor thread. So a 30-instance bounce using transform: translateY runs at consistent 60fps even on 3-year-old Android — because the CPU-side layout thread is never touched. This is the #1 mistake in CSS-bounce tutorials on Medium, dev.to, and old blog posts; every demo in this collection uses the compositor-safe pattern.bounceIn class in animate.css is a 5-stop keyframe on transform: scale + opacity. Reproducing it as vanilla scoped CSS costs 12 lines instead of 20KB of library CSS. The recipe: @keyframes bounceIn { 0% { opacity: 0; transform: scale(.3); } 20% { transform: scale(1.1); } 40% { transform: scale(.9); } 60% { opacity: 1; transform: scale(1.03); } 80% { transform: scale(.97); } 100% { opacity: 1; transform: scale(1); } } applied with animation: bounceIn .75s cubic-bezier(.34, 1.56, .64, 1) both;. The both keyword combines forwards + backwards — it applies the 100% state after the animation ends AND the 0% state before it starts, so the element sits invisible until the animation triggers. The five stops with alternating over/undershoot (1.1 → .9 → 1.03 → .97) create the rubber-ball rest-position oscillation. A 3-stop version (0% → 50% → 100%) feels mechanical because it's a smooth curve; the extra 2 stops are what make it read as physical. For directional variants — bounceInDown / bounceInUp / bounceInLeft / bounceInRight — add translateY(-40px) or translateX(40px) to the 0% and 20% stops alongside the scale. Demo #2 in this collection ships the exact bounceIn recipe applied to a SaaS pricing modal. No animate.css package, no framework, 12 lines of scoped CSS.animate-bounce as a preconfigured utility that maps to a bounce keyframe with animation: bounce 1s infinite. To customize, you have three tiers of approach depending on how much control you need. Tier 1 — arbitrary values (Tailwind v3+): animate-[bounce_1.5s_ease-in-out_infinite] uses arbitrary syntax to override duration and timing without touching tailwind.config.js. Fast for one-off tweaks. Tier 2 — extend the theme in tailwind.config.js: add theme.extend.animation.bounceSlow = 'bounce 2s ease-in-out infinite' then use animate-bounceSlow. This gives you a reusable named utility. Tier 3 — custom keyframes for full control over height and stops: register theme.extend.keyframes.customBounce = { '0%, 100%': { transform: 'translateY(0)' }, '30%': { transform: 'translateY(-20px)' }, '50%': { transform: 'translateY(-6px)' }, '70%': { transform: 'translateY(-14px)' } } paired with theme.extend.animation.customBounce = 'customBounce 2s ease-in-out infinite'. Then use animate-customBounce. The default animate-bounce peak is only -25% of the element's height (via translateY percent) which reads as subtle — for a more assertive bounce like the classic animate.css version, custom keyframes with pixel-based translateY(-20px) feel more physical. Demo #16 in this collection ships the full tailwind.config.js customization recipe alongside the equivalent scoped CSS.prefers-reduced-motion rule fires when users with vestibular disorders or motion sensitivity have set the system-level accessibility preference. The wrong response is to disable the animation entirely and lose the feedback signal — the user still needs to know their click registered. The right response depends on the animation's role. Arrivals (modals, checkmarks, toasts): skip the bounce, show the settled state instantly, add a 200ms opacity fade so the appearance isn't a jarring pop. The information ("this arrived") is preserved; only the celebration motion is disabled. Interactions (button hover bounce, add-to-cart shake): swap the bounce for an instant color state change — the button still gives feedback, just via color instead of motion. Playful/decorative (physics ball, floating badge, DVD screensaver): disable entirely. These carry no information; motion is the whole point, so removing it loses nothing meaningful. Error/alert wiggle: replace horizontal shake with a red border pulse — the "something is wrong" signal persists without the horizontal motion that triggers vestibular issues most severely. This tiered approach follows WCAG 2.3.3 (Animation from Interactions). Every demo in this collection ships its own tier-appropriate fallback in a @media (prefers-reduced-motion: reduce) block — check the demo's CSS panel to see the pattern for each intent tier.0% translateY(0) → 50% translateY(-200px) → 100% translateY(0), weight the timing curve so the fall is faster than the rise. Use animation-timing-function: cubic-bezier(.5, 0, .5, 1) on the falling half and cubic-bezier(.5, .5, .5, 1) on the rising half — or simpler, use ease-out for the rise (deceleration to peak) and ease-in for the fall (acceleration to floor). Squash-and-stretch: add scaleY and scaleX variations at the peak and floor. At the peak of the jump (100% up), the ball is at rest for a split second — apply scaleY(1.2) scaleX(.9) to elongate vertically. At the floor contact (return to translateY 0), apply scaleY(.7) scaleX(1.3) to flatten horizontally. This is the classic Disney animation principle — objects deform in the direction of motion. For the animation to loop convincingly, add a horizontal decay: translateX increments by a few pixels per cycle so the ball drifts sideways like a real bouncing ball losing energy laterally. Demo #11 in this collection ships the full recipe with all three effects combined.transform: scale or translateY with a multi-stop keyframe (0% → 40% overshoot → 70% undershoot → 100% settle) or a cubic-bezier with the second Y coordinate above 1. Direction: primarily vertical. Feels: physical, gravity-influenced. Use for: arrivals, click feedback, success confirmations. Pulse — radiating outward motion from a static center. A ring emanates from a button, a dot radiates. Signature: box-shadow outward-cast or transform: scale on a pseudo-element with opacity fading to 0. Direction: omnidirectional radial. Feels: alive, attention-signaling. Use for: CTAs, live status indicators, notifications. See our sibling CSS Pulse Animation collection for the full pulse vocabulary. Spring — sinusoidal oscillation around a rest position, damping to zero. Feels smoother than bounce (no hard "floor" contact). Signature: a multi-stop keyframe with 6-8 stops declining in amplitude, or a physics library like Framer Motion. Direction: any axis. Use for: playful UI, drag-release interactions. Elastic — snapping into position with rubber-band overshoot then quick settle. Similar to bounce but the overshoot is sharper and the settle is faster. Signature: a 3-stop cubic-bezier with negative first Y (undershoot before rise) and positive second Y (overshoot before settle). Direction: any. Feels: snappy, high-energy. Use for: modal entrances, toggle switches, tabs. The four terms overlap but the mental model helps you pick the right primitive for the job.20 hand-coded CSS animated buttons — neon glow, ripple, 3D press, liquid fill, jelly bounce, shine sweep, animated border, moving gradient CTA, text flip, submit success state, add-to-cart progress, download icon, hamburger-to-close, toggle switch, loading spinner inside button, next/prev arrow nav, and ghost button background reveal. Half pure CSS, half lightweight JS for production interactions.
11 pure CSS animation-timeline demos built on the W3C scroll() and view() spec — reading progress bar, view-timeline fade & reveal, shrinking sticky header, stacking cards, horizontal scroll section, parallax hero, container shadow indicators, reverse-scroll columns, text scrim reveal, cover card to sticky header, and image zoom / clip-path wipe. Zero JS, off the main thread, Core Web Vitals safe. Copy-paste ready.
25 hand-coded CSS background animations for SaaS hero sections, developer tool documentation, agency portfolios, gaming and Web3 landing pages, seasonal e-commerce campaigns, and dark-mode dashboards. Covers full-screen gradient shifts, animated mesh gradients, aurora borealis glow, cursor spotlight follow, interactive water ripples, dot grid and diagonal stripe patterns, SVG grain and noise texture overlays, topographic contour lines, layered SVG waves, plasma and lava lamp fluids, bokeh light blur, particle constellation networks, matrix digital rain, synthwave 3D perspective grids, starfield warp speed, CRT scanline overlays, fog and mist drift, morphing organic blobs, floating glassmorphism orbs, halftone dot patterns, starry night skies, floating geometric shapes, rising bubbles, and falling snow. 20 are pure CSS with zero JavaScript; the 5 that need it use vanilla canvas or pointer tracking with no dependencies. Every background animates compositor-only properties so it never blocks the main thread, is scoped under a .bga-NN prefix for no-collision pasting, guards prefers-reduced-motion, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.