
A pure CSS snippet that provides seven smoothly animated button hover effects using only the CSS box-shadow property and CSS custom properties.
Features:
- 7 effects:
fill,pulse,close,raise,up,slide, andoffset. - CSS custom properties: Colors are controlled via
--colorand--hoverCSS variables. - Inset shadow technique: Uses the
insetkeyword onbox-shadowto fake a fill animation from any direction. - Smooth stacked shadows: Where multiple shadows are needed, the snippet maintains the same shadow count on both the default and
:hoverstates. - Focus state support: Every
:hoverrule is paired with:focus.
See It In Action:
Use Cases:
- Call-to-Action Buttons: You can use the “Fill” or “Pulse” effects to draw attention to primary actions like “Sign Up” or “Buy Now.”
- Navigation Menus: The “Underline” or “Slide” effects work well for distinct hover states in navbar links.
- Form Submission: The “Raise” effect provides tactile feedback when a user interacts with submit buttons.
- Interactive Cards: You can apply the “Offset” shadow style to card components to give them depth on hover.
How To Use It:
1. Copy the full CSS snippet below. Each class defines its own --color and --hover CSS variables, then overrides box-shadow on :hover and :focus.
/* --- FILL: inset shadow expands from all edges simultaneously --- */
.fill {
--color: #a972cb;
--hover: #cb72aa;
}
.fill:hover,
.fill:focus {
/* A single inset shadow with 2em spread covers the full button face */
box-shadow: inset 0 0 0 2em var(--hover);
}
/* --- PULSE: radiating ring animation using @keyframes --- */
.pulse {
--color: #ef6eae;
--hover: #ef8f6e;
}
.pulse:hover,
.pulse:focus {
/* End state is transparent so the ring fades out after expanding */
animation: pulse 1s;
box-shadow: 0 0 0 2em transparent;
}
@keyframes pulse {
0% {
/* Ring starts at 0 radius in the hover color, then expands to 2em transparent above */
box-shadow: 0 0 0 0 var(--hover);
}
}
/* --- CLOSE: two inset shadows fill from left and right simultaneously --- */
.close {
--color: #ff7f82;
--hover: #ffdc7f;
}
.close:hover,
.close:focus {
/* Negative left offset (-3.5em) fills from the right; positive fills from the left */
box-shadow:
inset -3.5em 0 0 0 var(--hover),
inset 3.5em 0 0 0 var(--hover);
}
/* --- RAISE: shadow appears below and the button lifts via translateY --- */
.raise {
--color: #ffa260;
--hover: #e5ff60;
}
.raise:hover,
.raise:focus {
/* Negative spread (-0.4em) gives the shadow a soft underside edge */
box-shadow: 0 0.5em 0.5em -0.4em var(--hover);
transform: translateY(-0.25em); /* Lifts the button 0.25em upward */
}
/* --- UP: inset shadow fills from the bottom edge upward --- */
.up {
--color: #e4cb58;
--hover: #94e458;
}
.up:hover,
.up:focus {
/* Large negative top value (-3.25em) anchors the shadow at the bottom */
box-shadow: inset 0 -3.25em 0 0 var(--hover);
}
/* --- SLIDE: inset shadow sweeps in from the left --- */
.slide {
--color: #8fc866;
--hover: #66c887;
}
.slide:hover,
.slide:focus {
/* 6.5em left offset pushes the shadow origin to the left edge */
box-shadow: inset 6.5em 0 0 0 var(--hover);
}
/* --- OFFSET: resting state has a visible outer + inner corner shadow;
hover collapses the outer shadow and floods the inner one --- */
.offset {
--color: #19bc8b;
--hover: #1973bc;
}
.offset {
/* Two shadows create a "double border" corner effect at rest */
box-shadow:
0.3em 0.3em 0 0 var(--color),
inset 0.3em 0.3em 0 0 var(--color);
}
.offset:hover,
.offset:focus {
/* First shadow collapses to 0; second floods the button interior */
box-shadow:
0 0 0 0 var(--hover),
inset 6em 3.5em 0 0 var(--hover);
}2. Apply these hover effects to your DOM elements like buttons.
<button class="fill">Fill In</button> <button class="pulse">Pulse</button> <button class="close">Close</button> <button class="raise">Raise</button> <button class="up">Fill Up</button> <button class="slide">Slide</button> <button class="offset">Offset</button>
Alternatives:
- Hover.css: A comprehensive collection of CSS hover effects covering borders, shadows, text, and background transitions. It’s a broader library compared to this focused box-shadow approach.
- CSShake: Specializes in shake and vibration animations triggered on hover.
- Hover Effects: Discover more hover effects at CSSScript.com.
FAQs:
Q: Why are my hover transitions choppy on the offset button?
A: Your resting box-shadow and hover box-shadow have a different number of shadow layers. CSS interpolates between shadows position-by-position. If the count mismatches, the browser can’t calculate intermediate values and jumps directly between states.
Q: Can I apply multiple effects to the same button?
A: Technically yes, but the box-shadow property is a single list. Two effect classes will overwrite each other’s box-shadow on hover, and only the last rule in the cascade wins.
Q: Do these effects work on elements other than <button>?
A: Yes. The classes work on any block or inline-block element. For anchor tags, add display: inline-block so padding and shadow geometry are computed correctly.
Q: How do I adjust the fill speed?
A: Change the transition duration on the base button rule. The current value is 0.25s. Increasing it to 0.4s or 0.5s gives a more deliberate, cinematic feel.
Q: Is there a risk of these effects conflicting with a CSS reset or framework like Tailwind?
A: Yes, if your framework resets box-shadow to none via a utility class or base layer, the transitions will not animate — they’ll snap. Check that no utility class on the button overrides box-shadow at a higher specificity. In Tailwind, this means avoiding shadow-none on the same element, or adding the effect classes after the framework’s stylesheet in your <head>.






