21 examples Responsive Uses JS beginner

21 CSS Button Hover Effects

100% original, hand-coded from scratch. Pure CSS where possible. Copy any snippet and drop it straight into your project — no libraries, no frameworks, no dependencies.

21 unique effects 18 pure CSS 3 CSS + JS 0 dependencies
01 / 21
Liquid Fill
Pure CSS
Background floods upward like liquid filling a container via pseudo-element height transition.
.btn {
  position: relative;
  color: #7c6cff; background: transparent;
  border: 2px solid #7c6cff; overflow: hidden;
  transition: color 0.4s; z-index: 0;
}
.btn::before {
  content: '';
  position: absolute;
  bottom: -2px; left: -2px; right: -2px; height: 0;
  background: #7c6cff;
  transition: height 0.45s cubic-bezier(0.23,1,0.32,1);
  z-index: -1;
}
.btn:hover { color: #fff; }
.btn:hover::before { height: calc(100% + 4px); }
<button class="btn">Hover Me</button>
02 / 21
Magnetic Border
Pure CSS
A conic-gradient border spins into view on hover and the button lifts with a coloured glow.
.btn-wrap {
  position: relative; padding: 2px;
  border: none; background: none; cursor: pointer;
  border-radius: 8px; display: inline-block;
}
.btn-wrap::before {
  content: '';
  position: absolute; inset: -2px; border-radius: 10px;
  background: conic-gradient(
    #7c6cff, #ff6c8a, #3de8f5, #1ed98a, #7c6cff);
  opacity: 0; transition: opacity .3s;
  animation: border-spin 3s linear infinite paused;
}
.btn-wrap:hover::before {
  opacity: 1;
  animation-play-state: running;
}
@keyframes border-spin { to { transform: rotate(360deg); } }
.btn-inner {
  display: block; padding: 12px 32px; border-radius: 7px;
  background: #111118; color: #fff;
  font-size: 14px; font-weight: 600;
  transition: transform .3s, box-shadow .3s;
}
.btn-wrap:hover .btn-inner {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(124,108,255,.3);
}
<button class="btn-wrap">
  <span class="btn-inner">Magnetic Border</span>
</button>
03 / 21
Glitch Slice
Pure CSS
Two color-shifted clones slice through in staggered horizontal bands, simulating a signal glitch.
.btn { position: relative; overflow: hidden; }
.btn::before, .btn::after {
  content: attr(data-text);
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  opacity: 0;
}
.btn::before {
  background: #ff6c8a; color: #fff;
  clip-path: polygon(0 30%,100% 30%,100% 50%,0 50%);
}
.btn::after {
  background: #7c6cff; color: #fff;
  clip-path: polygon(0 55%,100% 55%,100% 75%,0 75%);
}
.btn:hover::before { animation: glitch1 0.3s steps(1) infinite; }
.btn:hover::after  { animation: glitch2 0.3s steps(1) infinite 0.05s; }
@keyframes glitch1 { 50% { opacity:1; transform:translateX(-4px); } }
@keyframes glitch2 { 50% { opacity:1; transform:translateX(4px);  } }
<button class="btn" data-text="GLITCH">GLITCH</button>
04 / 21
Neon Pulse
Pure CSS
Multi-layered box-shadows create a breathing neon glow that pulses rhythmically on hover.
.btn {
  color: #2ecc8a; border: 2px solid #2ecc8a;
  background: transparent; text-transform: uppercase;
  letter-spacing: 0.08em; transition: all 0.3s;
}
.btn:hover {
  background: rgba(46,204,138,0.1);
  animation: neonpulse 1.2s ease-in-out infinite;
}
@keyframes neonpulse {
  0%,100% { box-shadow: 0 0 12px #2ecc8a, 0 0 28px rgba(46,204,138,0.35); }
  50%      { box-shadow: 0 0 20px #2ecc8a, 0 0 50px rgba(46,204,138,0.55),
               0 0 80px rgba(46,204,138,0.2); }
}
<button class="btn">NEON</button>
05 / 21
Split Reveal
Pure CSS
The button splits at the centre — top half slides up, bottom half slides down — both halves show the same text.
.btn {
  position: relative; overflow: hidden;
  border: 2px solid rgba(255,255,255,.15);
  background: #17171f; color: #fff;
  font-size: 14px; font-weight: 600; cursor: pointer;
}
.btn-top {
  display: block;
  clip-path: polygon(0 0, 100% 0, 100% 50%, 0 50%);
  transition: transform .35s cubic-bezier(.23,1,.32,1);
}
.btn-bottom {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: #7c6cff;
  clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0 100%);
  transform: translateY(50%);
  transition: transform .35s cubic-bezier(.23,1,.32,1);
}
.btn:hover .btn-top    { transform: translateY(-50%); }
.btn:hover .btn-bottom { transform: translateY(0); }
<button class="btn">
  <span class="btn-top">Split Reveal</span>
  <span class="btn-bottom" aria-hidden="true">Split Reveal</span>
</button>
06 / 21
Diagonal Shutter
Pure CSS
A skewed gradient panel wipes diagonally across the button like a camera shutter opening.
.btn {
  position: relative; overflow: hidden; z-index: 0;
  border: 1px solid rgba(255,255,255,0.18);
  transition: color 0.3s, border-color 0.3s;
}
.btn::before {
  content: '';
  position: absolute; top: 0; left: -105%; width: 100%; height: 100%;
  background: linear-gradient(135deg, #7c6cff 0%, #ff6c8a 100%);
  transition: left 0.4s cubic-bezier(0.23,1,0.32,1);
  z-index: -1; transform: skewX(-15deg);
}
.btn:hover::before { left: 0; }
.btn:hover { border-color: transparent; }
<button class="btn">Hover Me</button>
07 / 21
Elastic Lift
Pure CSS
A hard bottom shadow creates a physical 3D effect — elastic cubic-bezier makes it bounce on hover.
.btn {
  background: #7c6cff; color: #fff; border: none;
  box-shadow: 0 4px 0 #4a3aad; transform: translateY(0);
  transition: transform 0.12s cubic-bezier(0.34,1.56,0.64,1),
              box-shadow 0.12s;
}
.btn:hover  { transform: translateY(-4px); box-shadow: 0 8px 0 #4a3aad; }
.btn:active { transform: translateY(2px);  box-shadow: 0 2px 0 #4a3aad; }
<button class="btn">Click Me</button>
08 / 21
Center Underline Draw
Pure CSS
A gradient underline expands symmetrically outward from the center of the button text.
.btn { position: relative; background: transparent; border: none; }
.btn::after {
  content: '';
  position: absolute; bottom: 5px;
  left: 50%; right: 50%; height: 2px;
  background: linear-gradient(90deg, #7c6cff, #ff6c8a);
  transition: left  0.4s cubic-bezier(0.23,1,0.32,1),
              right 0.4s cubic-bezier(0.23,1,0.32,1);
  border-radius: 2px;
}
.btn:hover::after { left: 32px; right: 32px; }
<button class="btn">Hover Me</button>
09 / 21
3D Flip
Pure CSS
The button flips on its X axis to reveal a second face — pure CSS 3D transform perspective.
.wrapper { perspective: 600px; display: inline-block; }
.btn {
  position: relative; display: block;
  transform-style: preserve-3d;
  transition: transform 0.5s cubic-bezier(0.23,1,0.32,1);
  background: transparent; border: none;
}
.front, .back {
  display: block; padding: 12px 32px;
  border-radius: 8px; backface-visibility: hidden;
}
.front { background: #ff6c8a; color: #fff; }
.back {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: #7c6cff; color: #fff; transform: rotateX(180deg);
}
.wrapper:hover .btn { transform: rotateX(180deg); }
<div class="wrapper">
  <button class="btn">
    <span class="front">Hover Me</span>
    <span class="back">Flipped!</span>
  </button>
</div>
10 / 21
Particle Burst
Pure CSS
Six colored dots shoot out in all directions from the center of the button on hover.
.btn { position: relative; overflow: visible; }
.dot {
  position: absolute; width: 6px; height: 6px; border-radius: 50%;
  top: 50%; left: 50%; margin: -3px 0 0 -3px; opacity: 0;
}
.btn:hover .dot { animation: burst 0.65s ease-out forwards; }
.dot:nth-child(1){background:#7c6cff;--dx:-52px;--dy:-42px;}
.dot:nth-child(2){background:#ff6c8a;--dx:52px;--dy:-42px;animation-delay:0.05s;}
.dot:nth-child(3){background:#2ecc8a;--dx:-62px;--dy:2px;animation-delay:0.02s;}
.dot:nth-child(4){background:#f5a623;--dx:62px;--dy:2px;animation-delay:0.07s;}
.dot:nth-child(5){background:#7c6cff;--dx:-36px;--dy:46px;animation-delay:0.04s;}
.dot:nth-child(6){background:#ff6c8a;--dx:36px;--dy:46px;animation-delay:0.03s;}
@keyframes burst {
  0%   { opacity: 1; }
  100% { transform:translate(var(--dx),var(--dy)) scale(0); opacity:0; }
}
<button class="btn">
  <span>Burst!</span>
  <span class="dot"></span>
  <span class="dot"></span>
  <span class="dot"></span>
  <span class="dot"></span>
  <span class="dot"></span>
  <span class="dot"></span>
</button>
11 / 21
Slide Doors
Pure CSS
Two panels slide in from opposite sides and meet in the middle to fill the entire button.
.btn { position: relative; overflow: hidden; }
.btn::before, .btn::after {
  content: ''; position: absolute; top: 0;
  width: 50%; height: 100%; background: #7c6cff;
  transition: transform 0.4s cubic-bezier(0.23,1,0.32,1);
}
.btn::before { left: 0;  transform: translateX(-101%); }
.btn::after  { right: 0; transform: translateX(101%); }
.btn .label { position: relative; z-index: 1; transition: color 0.4s; }
.btn:hover::before { transform: translateX(0); }
.btn:hover::after  { transform: translateX(0); }
.btn:hover .label { color: #fff; }
<button class="btn"><span class="label">Slide Doors</span></button>
12 / 21
Typewriter Retype
CSS + JS
Text erases and retypes itself character by character on hover — like a live terminal cursor.
.btn { font-family: monospace; }
.cursor {
  display: inline-block; width: 2px; height: 13px;
  background: currentColor; margin-left: 2px;
  vertical-align: middle; opacity: 0;
}
.btn:hover .cursor { animation: blink 0.6s step-end infinite; }
@keyframes blink { 0%,100%{ opacity:1; } 50%{ opacity:0; } }
<button class="btn">
  <span class="text">console.log()</span>
  <span class="cursor"></span>
</button>
const btn = document.querySelector('.btn');
const txt = btn.querySelector('.text');
const full = txt.textContent;

btn.addEventListener('mouseenter', () => {
  let i = full.length;
  const erase = setInterval(() => {
    txt.textContent = full.slice(0, --i);
    if (i === 0) { clearInterval(erase); retype(); }
  }, 55);
  function retype() {
    let j = 0;
    const write = setInterval(() => {
      txt.textContent = full.slice(0, ++j);
      if (j === full.length) clearInterval(write);
    }, 55);
  }
});
13 / 21
Hard Shadow Shift
Pure CSS
Brutalist hard offset shadow shifts both position and color on hover, snaps back on click.
.btn {
  color: #0a0a0f; background: #f0eeff;
  border: 2px solid #0a0a0f;
  text-transform: uppercase; letter-spacing: 0.07em; font-weight: 700;
  box-shadow: 4px 4px 0 #0a0a0f;
  transition: box-shadow 0.15s, transform 0.15s;
}
.btn:hover  { box-shadow: 8px 8px 0 #7c6cff; transform: translate(-2px,-2px); }
.btn:active { box-shadow: 2px 2px 0 #0a0a0f; transform: translate(2px,2px); }
<button class="btn">CLICK ME</button>
14 / 21
Ripple Wave
CSS + JS
A ripple circle radiates outward from the exact point of your click, like Material Design.
.btn { position: relative; overflow: hidden; }
.ripple {
  position: absolute; border-radius: 50%;
  background: rgba(255,255,255,0.32);
  transform: scale(0); animation: rwave 0.7s linear;
  pointer-events: none;
}
@keyframes rwave { to { transform: scale(4); opacity: 0; } }
<button class="btn">Click Me</button>
btn.addEventListener('click', (e) => {
  const c = document.createElement('span');
  const d = Math.max(btn.offsetWidth, btn.offsetHeight);
  const r = btn.getBoundingClientRect();
  c.className = 'ripple';
  c.style.cssText = `width:${d}px;height:${d}px;
    left:${e.clientX - r.left - d/2}px;
    top:${e.clientY - r.top  - d/2}px`;
  btn.appendChild(c);
  c.addEventListener('animationend', () => c.remove());
});
15 / 21
Rainbow Border Spin
Pure CSS
A conic-gradient border spins continuously using the CSS mask-composite technique.
.btn { position: relative; border: none; }
.btn::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: 8px; padding: 2px;
  background: conic-gradient(#7c6cff,#ff6c8a,#2ecc8a,#f5a623,#7c6cff);
  -webkit-mask: linear-gradient(#fff 0 0) content-box,
                linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; transition: opacity 0.3s;
}
.btn:hover::before { opacity: 1; animation: spin 2s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
<button class="btn">Hover Me</button>
16 / 21
Morph Shape
Pure CSS
The button border-radius morphs from rectangle to pill and color transitions simultaneously.
.btn {
  background: #ff6c8a; color: #fff; border: none;
  transition: border-radius 0.4s cubic-bezier(0.23,1,0.32,1),
              background 0.3s, transform 0.2s;
}
.btn:hover {
  border-radius: 50px;
  background: #7c6cff;
  transform: scaleX(0.92);
}
<button class="btn">Hover Me</button>
17 / 21
Icon Slide In
Pure CSS
An arrow slides in from outside as the button padding expands to make room for it.
.btn {
  position: relative; overflow: hidden;
  transition: padding 0.35s cubic-bezier(0.23,1,0.32,1);
}
.icon {
  position: absolute; right: -24px; top: 50%;
  transform: translateY(-50%); opacity: 0;
  transition: right 0.35s cubic-bezier(0.23,1,0.32,1), opacity 0.3s;
}
.btn:hover { padding-right: 52px; }
.btn:hover .icon { right: 16px; opacity: 1; }
<button class="btn">Get Started<span class="icon">→</span></button>
18 / 21
Cursor Spotlight
CSS + JS
A soft radial light follows your cursor around inside the button, illuminating where you hover.
.btn { position: relative; overflow: hidden; }
.glow {
  position: absolute; width: 100px; height: 100px; border-radius: 50%;
  background: radial-gradient(circle, rgba(124,108,255,0.28) 0%, transparent 70%);
  pointer-events: none; opacity: 0; transition: opacity 0.3s;
  transform: translate(-50%, -50%);
}
.btn:hover .glow { opacity: 1; }
<button class="btn">
  <span class="glow"></span>
  Hover Me
</button>
btn.addEventListener('mousemove', (e) => {
  const r = btn.getBoundingClientRect();
  glow.style.left = (e.clientX - r.left) + 'px';
  glow.style.top  = (e.clientY - r.top)  + 'px';
});
19 / 21
Stagger Fill
Pure CSS
Five vertical segments fill upward one by one in a cascading waterfall sequence.
.btn { position: relative; overflow: hidden; }
.seg {
  position: absolute; top: 0; width: 20%; height: 100%;
  background: #7c6cff; transform: scaleY(0); transform-origin: bottom;
  transition: transform 0.3s cubic-bezier(0.23,1,0.32,1);
}
.seg:nth-child(1){ left:  0%; transition-delay: 0s;    }
.seg:nth-child(2){ left: 20%; transition-delay: 0.04s; }
.seg:nth-child(3){ left: 40%; transition-delay: 0.08s; }
.seg:nth-child(4){ left: 60%; transition-delay: 0.12s; }
.seg:nth-child(5){ left: 80%; transition-delay: 0.16s; }
.label { position: relative; z-index: 1; transition: color 0.4s 0.1s; }
.btn:hover .seg { transform: scaleY(1); }
.btn:hover .label { color: #fff; }
<button class="btn">
  <span class="seg"></span>
  <span class="seg"></span>
  <span class="seg"></span>
  <span class="seg"></span>
  <span class="seg"></span>
  <span class="label">Hover Me</span>
</button>
20 / 21
Sunburst Expand
Pure CSS
Spinning conic-gradient rays fan out behind the button on hover, glowing like a sunburst.
.btn {
  position: relative; overflow: hidden;
  padding: 12px 40px; border-radius: 50px; border: none;
  background: #f5a84a; color: #0a0a0f;
  font-size: 14px; font-weight: 700; cursor: pointer;
  transition: transform .3s, box-shadow .3s;
}
.btn:hover {
  transform: scale(1.06);
  box-shadow: 0 8px 24px rgba(245,168,74,.5);
}
.btn-rays {
  position: absolute; inset: -40%;
  background: conic-gradient(
    transparent 0deg,   rgba(255,255,255,.2) 10deg,
    transparent 20deg,  rgba(255,255,255,.2) 30deg,
    transparent 40deg,  rgba(255,255,255,.2) 50deg,
    transparent 60deg,  rgba(255,255,255,.2) 70deg,
    transparent 80deg,  rgba(255,255,255,.2) 90deg,
    transparent 100deg, rgba(255,255,255,.2) 110deg,
    transparent 120deg, rgba(255,255,255,.2) 130deg,
    transparent 140deg, rgba(255,255,255,.2) 150deg,
    transparent 160deg, rgba(255,255,255,.2) 170deg,
    transparent 180deg, rgba(255,255,255,.2) 190deg,
    transparent 200deg, rgba(255,255,255,.2) 210deg,
    transparent 220deg, rgba(255,255,255,.2) 230deg,
    transparent 240deg, rgba(255,255,255,.2) 250deg,
    transparent 260deg, rgba(255,255,255,.2) 270deg,
    transparent 280deg, rgba(255,255,255,.2) 290deg,
    transparent 300deg, rgba(255,255,255,.2) 310deg,
    transparent 320deg, rgba(255,255,255,.2) 330deg,
    transparent 340deg, rgba(255,255,255,.2) 350deg);
  opacity: 0; transition: opacity .3s;
}
.btn:hover .btn-rays {
  opacity: 1;
  animation: sunburst-spin 6s linear infinite;
}
@keyframes sunburst-spin { to { transform: rotate(360deg); } }
.btn-label { position: relative; z-index: 1; }
<button class="btn">
  <div class="btn-rays"></div>
  <span class="btn-label">Sunburst</span>
</button>
21 / 21
3D Press
Pure CSS
Layered box-shadows create a physical 3D extrusion. Hovering lifts the button; clicking presses it flush into the surface.
.btn {
  background: #7c6cff; color: #fff; border: none;
  border-radius: 8px;
  box-shadow:
    0 6px 0 #4a3ab0,
    0 8px 16px rgba(74,58,176,.4);
  transition:
    transform .15s cubic-bezier(.23,1,.32,1),
    box-shadow .15s cubic-bezier(.23,1,.32,1);
}
.btn:hover {
  transform: translateY(-3px);
  box-shadow:
    0 9px 0 #4a3ab0,
    0 14px 24px rgba(74,58,176,.45);
}
.btn:active {
  transform: translateY(4px);
  box-shadow:
    0 2px 0 #4a3ab0,
    0 4px 8px rgba(74,58,176,.3);
}
<button class="btn">3D Press</button>

Related collections