30 CSS Shake Animations
30 hand-coded CSS shake animation topics, each shipping 2–3 side-by-side variants so you can pick the exact treatment for your surface — form-error recoils, login box shakes, button attention wiggles, notification bell rings, cart wiggles, icon micro-interactions, elastic springs, 3D judders, and hit-damage / screen shakes for browser games. Every form demo pairs motion with color + border + aria-invalid so the state reads without motion perception. Scoped under .shk-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.
Related16 CSS Glitch Text Effects16 CSS Bounce Animations30 CSS Keyframe Animations
Course pickPartner: Zero to Mastery
Affiliate linkWant to build production-ready CSS layouts, animations and UI from scratch?
You just browsed 30 shake animations. Learn the Flexbox, Grid and animation thinking behind them, so the next component starts in your head, not in a copy-paste.
Every ZTM course in one membership: $25/month, paid yearly at $299 · 30‑day money-back guarantee
The CSS Bootcamp. We may earn a commission, at no extra cost to you.
02. CSS Shake Form on Submit Error (opens in a new tab)
03. CSS Password Error Shake Effect (opens in a new tab)
04. CSS Input Field Shake on Wrong Value (opens in a new tab)
05. Shake Input Box CSS Keyframes (opens in a new tab)
06. CSS Shake Text on Error (opens in a new tab)
07. CSS Form Validation Failure Shake (opens in a new tab)
08. Shake Login Box CSS (opens in a new tab)
09. CSS Shake Button on Hover (opens in a new tab)
10. CSS Button Shake on Click (opens in a new tab)
11. Shake Button CSS Keyframes (opens in a new tab)
12. CSS Buy Now Button Attention Shake (opens in a new tab)
13. CSS Subtle Shake Hover Effect (opens in a new tab)
14. Disabled Button Shake CSS (opens in a new tab)
15. CSS Notification Bell Shake Animation (opens in a new tab)
16. CSS Shopping Cart Wiggle on Item Add (opens in a new tab)
17. CSS Lock Icon Shake Animation (opens in a new tab)
18. CSS Card Shake Effect on Hover (opens in a new tab)
19. CSS Alert Badge Shake Animation (opens in a new tab)
20. CSS Heart Icon Pulse and Shake (opens in a new tab)
21. CSS Trash Icon Shake on Drag Over (opens in a new tab)
22. CSS Horizontal Shake Keyframes (opens in a new tab)
23. CSS Vertical Shake Animation (opens in a new tab)
24. CSS Skew Shake Animation (opens in a new tab)
25. CSS Aggressive Shake Animation (opens in a new tab)
26. CSS Gentle Continuous Shake Animation (opens in a new tab)
27. CSS Elastic Shake Effect (opens in a new tab)
28. CSS 3D Shake Transform (opens in a new tab)
29. CSS Hit Damage Shake Effect for Web Games (opens in a new tab)
30. CSS Screen Shake Effect Keyframes (opens in a new tab)
Frequently asked questions
What is a CSS shake animation and what is the canonical recipe?
transform — used almost exclusively as a micro-interaction to signal state change: form validation failure, wrong password, button attention pull, notification arrival, cart item added, incoming hit / damage in a browser game, or a full-viewport screen shake for a big narrative moment. It's distinct from bounce (a vertical elastic drop / settle), glitch (a RGB channel-split chromatic aberration), wobble (a slower rotational sway), and pulse (a scale-based attention loop). The canonical recipe in 20 lines: @keyframes shake { 10%, 90% { transform: translateX(-1px); } 20%, 80% { transform: translateX(2px); } 30%, 50%, 70% { transform: translateX(-4px); } 40%, 60% { transform: translateX(4px); } } paired with .shake { animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both; transform: translate3d(0, 0, 0); backface-visibility: hidden; perspective: 1000px; }. The critical details most tutorials get wrong: (1) animate transform only — NEVER margin / left / right, those trigger layout thrash and scrollbars dance during the shake; (2) use asymmetric offsets (10%/20%/30% etc.) rather than a plain sine wave — real shakes decay, they don't cycle; (3) force GPU compositor promotion with translate3d(0,0,0) + backface-visibility: hidden so the animation runs on the compositor thread (zero INP hit); (4) animation-fill-mode: both so the element returns to its rest position cleanly after the shake; (5) wrap in @media (prefers-reduced-motion: reduce) { animation: none; } — non-optional per WCAG 2.3.3. This collection ships 30 topics × 2–3 variants each covering every canonical use case: invalid-input error shakes, form-submit failure recoils, password wrong-attempt shakes, hover attention wiggles, notification bell rings, cart wiggles, icon micro-interactions, and gaming screen shakes.Which shake animation should I pick for my use case?
translateX shake paired with a red border + inline error message (never just the shake — WCAG 1.4.1 Use of Color forbids relying on motion alone). Login box wrong-password recoil: topic 08 — same technique scoped to the whole card, not just the input, so the visual weight matches the emotional weight of a failed auth. Button hover attention pull (CTAs, sale banners, limited-time offers): topics 09–13 — subtle 2–3px shakes triggered on :hover, always paired with a color/scale change so touch users still get feedback. Buy-now / add-to-cart CTA: topic 12 — the retail attention-shake used by Amazon / Shopify / Etsy default themes to break tunnel vision on a static product page. Disabled state feedback: topic 14 — a soft shake when a user clicks a disabled button, communicating "this is intentionally blocked" better than a static grey pill. Notification bell arriving: topic 15 — the SaaS / Slack / Discord / GitHub pattern where a bell wiggles when a new notification lands, drawing eye to the badge count. Shopping cart add-to-cart: topic 16 — the e-commerce affordance that confirms the item was added AND says "go check your cart." Lock icon wrong password: topic 17 — a small icon shake in the auth field, complements the form shake above. Alert badge / notification count: topic 19 — periodic gentle shake to draw attention without spamming motion. Heart / like button: topic 20 — the Instagram / Twitter / TikTok double-tap shake-and-pulse combo. Trash icon drag-over: topic 21 — the drag-and-drop trash affordance shake, signalling the drop target is active. Continuous gentle wiggle: topic 26 — decorative onboarding pointers, notification-empty state loading, error-empty state. Elastic spring shake: topic 27 — modern linear() spring easing (Chrome 113+, Safari 17.2+, Firefox 112+) for the newest tier of natural motion. Web game hit damage: topics 29–30 — HTML5 game UI-layer damage cues (health bar hit, boss attack), works alongside canvas / WebGL for the actual gameplay. Rule of thumb: always pair shake with a non-motion cue — color, border, icon, text — so the state reads without motion perception (see the accessibility FAQ below).How do I re-trigger a CSS shake animation on repeated invalid submissions?
.shake class → let it play → in the animationend event listener, remove the class. On next invalid submit, add the class again → animation fires cleanly. Code: function shakeIt(el) { if (el.classList.contains('shake')) return; el.classList.add('shake'); el.addEventListener('animationend', () => el.classList.remove('shake'), { once: true }); }. The { once: true } auto-cleans the listener; the initial guard prevents re-adds mid-shake. This is what every demo in topics 01–08 uses. 2. Modern :user-invalid pseudo-class (Chrome 119+, Safari 17+, Firefox 88+): CSS can now trigger the shake purely on the browser's native validation state — input:user-invalid { animation: shake 0.5s both; }. Each time the browser flips :user-invalid from off → on (i.e., the user tries to submit and validation fails), the animation replays automatically. Zero JavaScript. Fallback to approach 1 for older browsers via @supports (selector(:user-invalid)). 3. The void-offsetWidth reflow hack (DEPRECATED — do not use): el.classList.remove('shake'); void el.offsetWidth; el.classList.add('shake');. The void el.offsetWidth forces a synchronous layout reflow, which resets the animation state. It works, but it's a 10–30ms main-thread block per shake — measurable INP hit, especially on mid-tier Android. Every 2019-era tutorial recommends this pattern; it's since been superseded by animationend cleanup (no reflow, no INP cost) and :user-invalid (no JS at all). Bonus gotcha: if your form uses React / Vue / Svelte, the framework may batch state updates and skip the class-toggle. Add the class via a ref imperatively OR use flushSync (React 18+) to force the intermediate render.Are CSS shake animations accessible? What about WCAG 2.3.3, prefers-reduced-motion, and vestibular disorders?
prefers-reduced-motion: reduce is set. Every demo in this collection ships @media (prefers-reduced-motion: reduce) { .shake { animation: none; } } AND a non-motion fallback — a solid red border + inline error message so the state still reads. 2. Motion is never the sole signal (WCAG 1.4.1 Use of Color, applied to motion): a form field shake alone is not a valid error indication. The user with reduced motion disabled sees nothing. Every demo pairs the shake with (a) a color change (usually red-500), (b) a border-style change (dashed or thicker), (c) an inline text error (aria-live="polite" region), AND (d) the aria-invalid="true" attribute for screen readers. Removing any one weakens the accessibility signal. 3. Semantic HTML for form validation: use <form novalidate> so you can control validation timing (the browser's default HTML5 validation is jarring and hard to style). Every input has required / type="email" etc. so :user-invalid and aria-invalid work. Error text sits in an aria-live="polite" region below the field so screen readers announce it without interrupting the user mid-typing. 4. Regulatory frameworks: US ADA + Section 508 + EU EAA (enforcement began June 2025) + Canada ACA + UK Equality Act 2010 + Australian DDA all require WCAG 2.2 AA compliance for public-facing digital products. Lawsuits under all six have specifically cited animations that didn't honour prefers-reduced-motion. Domino's Pizza (2019, US Supreme Court denied cert) and Beyoncé.com (2019) both involved this exact issue. Test in browser: Chrome DevTools > Rendering panel > "Emulate CSS media feature prefers-reduced-motion" > reduce. Then submit every form on the page — the shake should NOT fire, but the error state should still communicate.CSS shake vs Animate.css .shake vs Framer Motion / GSAP / anime.js — how do they compare?
.shake class matches roughly what this collection ships as topic 01, but the whole library ships together — you can't tree-shake a single animation. If you only need shake, this collection's ~40-line snippet is 99.5% smaller than the whole Animate.css bundle. Framer Motion (~60KB minified, ~5M weekly downloads): React-specific, declarative API. Shake via <motion.div animate={{ x: [0, -4, 4, -4, 4, 0] }} transition={{ duration: 0.5 }}>. Adds 60KB of runtime just for shake — worth it if you already use Framer Motion for other animations, wasteful otherwise. GSAP (~23KB core, free): general-purpose animation engine. GSAP's shake is via gsap.to(el, { x: 'random(-4, 4)', duration: 0.05, repeat: 10, yoyo: true }). More flexible but same story — 23KB core + GSAP-specific API to learn. anime.js (~17KB): shake via anime({ targets: el, translateX: [-4, 4, -4, 4, 0], duration: 500 }). Same tradeoff. react-shake / shake.js / wobble.js: single-purpose libraries. Even at 2–5KB, they're dependencies to update + audit for CVEs. Web Animations API (WAAPI, native): el.animate([{ transform: 'translateX(-4px)' }, { transform: 'translateX(4px)' }, { transform: 'translateX(0)' }], { duration: 500 }). Zero deps, works in every modern browser, but requires JS to trigger. What this collection gives you: pure CSS keyframes + optional animationend cleanup JS (10 lines). Zero bundle cost, zero runtime dependency, zero CVE surface, faster First Contentful Paint. For the 90% of shake use cases (form errors, button attention, notification bell, cart wiggle), the pure-CSS approach wins on every Core Web Vitals dimension. Reach for a library only if you (a) already use it for other animations, (b) need runtime-computed shake intensity (dynamic amplitude based on user data), or (c) need chained shake sequences with precise callbacks.Tailwind / shadcn / MUI / Chakra / Mantine / Ant Design shake — how do these compare?
animate-shake on the element. keyframes: { shake: { '10%, 90%': { transform: 'translateX(-1px)' }, '20%, 80%': { transform: 'translateX(2px)' }, '30%, 50%, 70%': { transform: 'translateX(-4px)' }, '40%, 60%': { transform: 'translateX(4px)' } } }, animation: { shake: 'shake 0.5s cubic-bezier(.36,.07,.19,.97) both' }. In Tailwind v4 (CSS-first config): @keyframes shake { ... } @utility animate-shake { animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both; }. Every demo in this collection includes the equivalent Tailwind arbitrary-utility recipe in its customization field. shadcn/ui: does not ship shake; the community pattern is to write the keyframes in your global CSS + add the class conditionally in the component. Chakra UI: has <Box animation={${shakeAnim} 0.5s}> with a keyframes helper — closest to first-class support but you still author the shake yourself. MUI / Material UI: sx={{ animation: 'shake 0.5s' }} + a global keyframes definition. Same as Chakra. Ant Design / Mantine / HeadlessUI / Radix: no built-in shake; author your own or copy from this collection. Recommendation: the shake is small enough (~40 lines including the reduced-motion guard) that authoring it once in your global CSS + calling it via any of the above libraries is faster than reaching for a shake-specific dependency. Every demo in this collection is drop-in ready — copy the css tab into your global stylesheet, copy the class name into your framework of choice, done.What's the correct semantic HTML pattern for a CSS shake on form validation error?
<form novalidate> — the novalidate attribute disables the browser's default validation UI so you can control the timing (browser default fires on blur, which is jarring during typing). 2. Input with real validation attributes: <input type="email" required aria-invalid="false" aria-describedby="email-error">. The type="email" and required attributes enable the browser's constraint validation API — you can then use input.validity.valid in JS and input:user-invalid in CSS. The aria-invalid starts "false"; JS flips it to "true" on validation failure so screen readers announce the error state. The aria-describedby links to the error message container. 3. Error message region: <div id="email-error" role="alert" aria-live="polite"></div>. The role="alert" + aria-live="polite" combination announces the error to screen readers without interrupting the user mid-typing. Populate the div's textContent with the human-readable error on validation failure; clear it on success. 4. Label: real <label for="email">Email address</label> — never rely on placeholder alone; the placeholder disappears on focus and screen readers don't announce it as reliably. 5. Submit handler: form.addEventListener('submit', e => { e.preventDefault(); if (!form.checkValidity()) { shakeInvalidFields(form); return; } submitForm(); });. The checkValidity() call runs constraint validation without showing the browser's default popup. shakeInvalidFields iterates form.querySelectorAll(':invalid'), sets aria-invalid="true", updates the error message, and adds the shake class with the animationend-cleanup pattern from the re-trigger FAQ above. 6. Success reset: on successful submit, clear aria-invalid, empty the error region, and remove the shake class. Regulatory context: this exact pattern is what ADA / Section 508 / EU EAA / WCAG 2.2 AA audits expect. Skip any step and you fail on WCAG 4.1.3 (Status Messages) or 3.3.1 (Error Identification) or 1.4.1 (Use of Color). Every form demo in this collection ships all six steps.Screen shake / hit damage for web games — CSS vs canvas vs WebGL?
<div class="hud"> costs zero canvas render time, runs on the compositor thread (no game loop stall), and is trivially disabled via prefers-reduced-motion. Pattern: @keyframes hit-shake { 0%, 100% { transform: translateX(0); } 20%, 60% { transform: translateX(-8px); } 40%, 80% { transform: translateX(8px); } } applied on hit-detection via a class toggle. Canvas / WebGL wins for camera shake: when the entire game viewport needs to shake in response to a big attack, explosion, or environmental event, you need to shake the render context itself — otherwise UI-layer shake looks disconnected from the gameplay it's reacting to. In canvas: ctx.translate(shakeX, shakeY) inside the game loop, with shakeX and shakeY decayed each frame. In WebGL (Three.js / Babylon / PIXI): apply the shake to the camera transform. Combining both: the strongest game-feel combines a subtle camera shake in canvas with a punchy CSS shake on the HUD elements — the two motions layer to create the "something big just happened" feeling without either being overwhelming alone. Performance ceiling: CSS shake on 5+ HUD elements simultaneously stays at 60fps on mid-tier Android. Canvas shake at 60fps depends entirely on your render complexity — profile with Chrome DevTools Performance panel. Reduced motion: game camera shake is arguably essential to gameplay (damage feedback), so prefers-reduced-motion should either scale it down to 20% amplitude OR replace it with a screen-flash / border-flash + damage-number pop-in. Never silently drop the damage cue — the user still needs to know they took a hit. Framework libraries: Phaser 3 has camera.shake(duration, intensity); PIXI.js has @pixi/filter-shockwave; Three.js requires manual camera shake. All good for the gameplay layer. This collection covers the CSS/UI-layer half.Related collections
20 CSS Animated Buttons
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 CSS animation-timeline Demos
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 CSS Background Animations
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.


























