
👀 Animated CSS button: shake and pulse effects in 10 minutes
A user scrolls the page, skims headings, images, and lists. The "Sign Up" button blends into the background and goes unnoticed. The form below it has had zero submissions for three days. A classic scenario: the button exists, but clicks don't.
The solution isn't a $500 redesign or a landing page rewrite. Thirty lines of CSS are enough. A subtle animation (a shake, pulse, or glow) makes the eye catch the button without annoying flashing. Research by Nielsen Norman Group confirms that moving elements attract attention 3 times faster than static ones, but only when the motion is justified and doesn't compete with the main content.
Below are three working animated CTA button options with ready-to-use code. From a simple shake to a combined pulse-glow. Copy and paste.
💡 Quick overview:
- HTML skeleton: minimal button markup with a modifier class that can be embedded in any form or landing page.
- Shake effect: the button shakes every 4 seconds via
@keyframes, drawing attention to the main action without irritating the user. - Pulse effect: a soft shadow pulse, an alternative for sites where shake feels too aggressive.
- CodePen demo: a live example where you can tweak settings and see results before adding to your site.
HTML markup: animated button skeleton
The markup is intentionally simple. No frameworks, just pure HTML. One button, one class.
1 <input type="submit" name="submit" value="Get Ticket!" 2 class="animated-btn animated-btn--shake">
Three points worth noting right away. First: type="submit" means the button works inside any form without additional JavaScript. Second: value is the text the user will see. Change it to whatever you need: "Download," "Sign Up," or anything else. Third: the modifier class animated-btn--shake controls the animation type. Replace it with --pulse or --glow to get a different effect without touching the markup.
If you're inserting the button outside a form, wrap it in <a href="..."> and replace input with <button>. The styles below work with both options.
CSS animation: shake effect
Shake is the most noticeable of the three effects. The button jiggles left and right by 3-5 pixels every 4 seconds. A user scrolls the page, catches the movement in peripheral vision, and shifts their gaze to the button. Four seconds is enough to prevent the animation from becoming annoying spam.
1 /* === Shake button === */ 2 .animated-btn--shake { 3 animation: shake 4s ease-in-out infinite; 4 transform-origin: center center; 5 } 6 7 @keyframes shake { 8 0%, 100% { transform: translateX(0); } 9 2% { transform: translateX(-4px) rotate(-1deg); } 10 4% { transform: translateX(4px) rotate(1deg); } 11 6% { transform: translateX(-3px); } 12 8% { transform: translateX(3px); } 13 10% { transform: translateX(0); } 14 }
Let's break down the key decisions. animation: shake 4s ease-in-out infinite: in our example, the full cycle takes several seconds, but the animation is active for only a small fraction of that time. The rest of the time, the button stays still. This matters: constant shaking is irritating, while measured motion attracts.
transform-origin: center center fixes the rotation point at the center so the button doesn't "drift" sideways during rotation.
rotate() at 1 degree adds realism. Pure translateX looks mechanical; a slight tilt creates the illusion of physical force, as if someone tugged the button on a string.
Add styling to match your design: background color via background, corner rounding with border-radius, padding, and font size with font-size. The animation doesn't depend on styling and works with any colors and sizes.
Variation: pulse effect
Shake isn't appropriate everywhere. On a corporate bank or medical clinic website, a shaking button looks out of place. Pulse provides a calmer way to draw attention: the button's shadow smoothly expands and contracts, creating a "breathing" effect.
1 /* === Pulse button === */ 2 .animated-btn--pulse { 3 animation: pulse 3s ease-in-out infinite; 4 } 5 6 @keyframes pulse { 7 0%, 100% { box-shadow: 0 0 0 0 rgba(46, 139, 87, 0.5); } 8 50% { box-shadow: 0 0 0 12px rgba(46, 139, 87, 0); } 9 }
The shadow expands from the button by 12 pixels and fades to transparency. The cycle is 3 seconds, slightly faster than shake, because pulsing is less intrusive and the eye forgives a quicker rhythm.
Substitute your own color in rgba(). The formula: take the button's main color and set its alpha to 0.5 in the starting keyframe and 0 in the ending one. For a green button, use rgba(46, 139, 87, 0.5); for blue, use rgba(41, 128, 185, 0.5).
You can combine shake and pulse on the same button, but we don't recommend it. Two simultaneous motions conflict and look messy. Choose one based on the site's character and audience.
CodePen: live example
We've posted ready-to-use code with both animation options on CodePen. Open it, change the duration, colors, padding, and watch the results in real time.
Embedding on a site via Additional CSS (Appearance → Customize → Additional CSS) takes a minute. Copy the block you need, paste it, save. A button in your theme's markup or form plugin will pick up the styles by class.
If you use WordPress, the path is even shorter: go to the admin panel, open the page or post in the editor, find the button, and add the class animated-btn animated-btn--shake in the block settings. Place the styles in Additional CSS, and they'll load on the front end without editing theme files.
The video above is a hands-on tutorial for creating the shake effect from scratch. The author demonstrates the process in real time: from markup to final tweaks in DevTools (English, 4 minutes).
⁉️🤔 Frequently asked questions
Will the animation slow down page loading?
Thirty lines of CSS weigh less than 1 KB even without compression. No additional libraries, no JavaScript. Page load time won't change. For comparison: a single Font Awesome icon averages 2-3 KB.
Does the animation work on mobile?
Yes,
transformandbox-shadoware hardware-accelerated on iOS and Android starting from 2016 versions. The only caveat: Safari before version 15 sometimes stuttersbox-shadowduring frequent repaints. Fix this by addingwill-change: box-shadowto the pulse button.
How do I disable animation for users with vestibular disorders?
Wrap the animation in
@media (prefers-reduced-motion: no-preference). Then, if the "Reduce motion" setting is enabled in the OS, the button will remain static. Modern browsers have supported this media query since 2019.
Can I trigger the animation only on hover?
Replace
infinitewithnonein theanimationproperty, then describe the hover state separately:.animated-btn:hover { animation: shake 0.4s ease-in-out; }. The button will shake once on hover and stop. This works for situations where autonomous animation conflicts with the design.
Why isn't my button animating after I paste the code?
Three common reasons: the class was copied incorrectly (check for
animated-btn--shakewith two hyphens); the theme's CSS file overridesanimation(add!importantor increase selector specificity); the button is inside a container withoverflow: hiddenthat clips the pulse shadow.
To animate or not to animate: the final breakdown
Shake effect, pulse effect, or a static button: the choice comes down to context, not trends. A commercial landing page with a single CTA button? Shake every 4 seconds, no question. An admin panel or dashboard with dozens of buttons on screen? Keep them static and animate only the main action. A corporate site with a conservative audience? Pulse highlight, minimalist and respectable.
A rule we've derived from dozens of A/B tests: an animated button increases conversion by a few percentage points, provided the animation is unique and doesn't compete for attention with neighboring elements. Two animated buttons side by side means lower conversion because the user gets confused and clicks neither.
Copy the code from the section above, adapt the colors and duration for your project. If you like the result, check out our selection of caching plugins. They'll help maintain site speed even with a dozen animated elements on the page.



