Skip to content
· 14 min read · 0 views

CSS Hover Effects Part 2 — 14 More Interactive Animations

14 more CSS hover effects with full code: text swap, zoom rotate, border spin, sink, color shift, underline grow, 3D tilt, sweep, shine line, expand border, backdrop, raise, skew, and icon swap.

// table of contents (29 sections)

Try them live — All 14 hover effects are available on CSSKit where you can customize parameters and copy the code. Source code on GitHub. See also Part 1 — Hover Effects and Part 1 — Text Effects.


In Part 1 we built 10 hover effects covering fills, underlines, borders, and flips. This post continues with 14 more — from 3D perspective tilts to spinning gradient borders. Together, that’s all 24 hover effects from CSSKit. Every one is pure CSS with customizable properties.

31. Text Swap

Text slides up and is replaced by new text on hover — perfect for CTAs.

How It Works

Two text elements share the same space. The original sits normally, while the replacement starts at translateY(100%) below it. On hover, the original slides up and out (translateY(-100%)) while the replacement slides in (translateY(0)). The overflow: hidden and fixed height on the parent clip the moving text.

.hover-swap {
  --hsw-color: #3b82f6;
  --hsw-speed: 0.3s;
  display: inline-block;
  padding: 14px 32px;
  border-radius: 10px;
  background: var(--hsw-color);
  color: #fff;
  font-weight: 600;
  font-size: 15px;
  font-family: system-ui, sans-serif;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  height: 48px;
  line-height: 20px;
}

.hover-swap-text {
  display: block;
  transition: transform var(--hsw-speed) ease;
}

.hover-swap-alt {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translateY(100%);
  transition: transform var(--hsw-speed) ease;
}

.hover-swap:hover .hover-swap-text {
  transform: translateY(-100%);
}

.hover-swap:hover .hover-swap-alt {
  transform: translateY(0);
}
<div class="hover-swap"><span class="hover-swap-text">Submit</span><span class="hover-swap-alt">Send →</span></div>

Tip: Change translateY to translateX for a horizontal swap, or combine both for a diagonal replacement.


32. Zoom Rotate

Smooth zoom with a slight rotation on hover — adds energy and movement.

How It Works

On hover, transform: scale(1.12) rotate(3deg) combines a 12% size increase with a subtle 3-degree tilt. A large box-shadow adds depth, and the border color shifts to blue for an accent highlight. All three properties transition at the same speed so they feel synchronized.

.hover-zoom {
  --hz-color: #1e293b;
  --hz-scale: 1.12;
  --hz-rotate: 3deg;
  --hz-speed: 0.3s;
  width: 200px;
  height: 140px;
  border-radius: 14px;
  background: var(--hz-color);
  border: 1px solid #374151;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: system-ui, sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: #94a3b8;
  cursor: pointer;
  transition: transform var(--hz-speed) ease, box-shadow var(--hz-speed) ease, border-color var(--hz-speed) ease;
}

.hover-zoom:hover {
  transform: scale(var(--hz-scale)) rotate(var(--hz-rotate));
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
  border-color: #3b82f6;
}
<div class="hover-zoom">Hover me</div>

Tip: Use negative rotation (-3deg) for a left tilt, or increase to 8deg for a more dramatic tilt.


33. Border Spin

A spinning conic-gradient border rotates around the element on hover.

How It Works

Three layers stack on top of each other. ::before is a conic-gradient that extends 2px beyond the element (inset: -2px) and rotates via @keyframes. ::after covers the inside with white, creating the “border only” illusion. On hover, ::before fades in with opacity: 1. The result is a colorful gradient border that continuously spins.

.hover-border-spin {
  --hbs-color1: #f43f5e;
  --hbs-color2: #3b82f6;
  --hbs-speed: 1.5s;
  position: relative;
  width: 120px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: #334155;
  background: #ffffff;
  border-radius: 8px;
  overflow: hidden;
}

.hover-border-spin::before {
  content: '';
  position: absolute;
  inset: -2px;
  background: conic-gradient(from 0deg, var(--hbs-color1), var(--hbs-color2), var(--hbs-color1));
  border-radius: 10px;
  z-index: -1;
  opacity: 0;
  transition: opacity 0.3s;
  animation: hbs-spin var(--hbs-speed) linear infinite;
}

.hover-border-spin:hover::before {
  opacity: 1;
}

.hover-border-spin::after {
  content: '';
  position: absolute;
  inset: 2px;
  background: #ffffff;
  border-radius: 6px;
  z-index: -1;
}

@keyframes hbs-spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
<div class="hover-border-spin">Hover Me</div>

Tip: Add more colors to the conic-gradient for a rainbow border: var(--hbs-color1), var(--hbs-color2), #22c55e, var(--hbs-color1).


34. Sink Down

Element sinks down with shrinking shadow — simulates a physical button press.

How It Works

The default state has a thick bottom shadow (box-shadow: 0 6px 0) creating a raised 3D button. On hover, translateY(4px) pushes the button down while the shadow shrinks to 0 2px 0 — making it look pressed in. The shadow color matches a darker shade of the button (#4338ca for a #6366f1 button).

.hover-sink {
  --hs-color: #6366f1;
  --hs-speed: 0.3s;
  width: 140px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: #ffffff;
  background: var(--hs-color);
  border-radius: 10px;
  cursor: pointer;
  box-shadow: 0 6px 0 #4338ca, 0 8px 16px rgba(99, 102, 241, 0.3);
  transition: transform var(--hs-speed) ease, box-shadow var(--hs-speed) ease;
}

.hover-sink:hover {
  transform: translateY(4px);
  box-shadow: 0 2px 0 #4338ca, 0 4px 8px rgba(99, 102, 241, 0.2);
}
<div class="hover-sink">Sink</div>

Tip: Add :active with translateY(6px) and box-shadow: 0 0 0 for a full press on click.


35. Color Shift

Background shifts through the hue spectrum on hover — smooth rainbow transition.

How It Works

The simplest effect in this list — just filter: hue-rotate(120deg) on hover. This shifts all colors by 120 degrees on the color wheel. A blue button becomes green, a red becomes yellow. The transition on filter makes it smooth. It’s a one-line change that creates a dramatic visual difference.

.hover-color-shift {
  --hcs-speed: 0.6s;
  width: 140px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: #ffffff;
  background: #3b82f6;
  border-radius: 10px;
  cursor: pointer;
  transition: filter var(--hcs-speed) ease, background var(--hcs-speed) ease;
}

.hover-color-shift:hover {
  filter: hue-rotate(120deg);
  background: #3b82f6;
}
<div class="hover-color-shift">Shift</div>

Tip: Use hue-rotate(180deg) for the complementary color, or hue-rotate(90deg) for an analogous shift.


36. Underline Grow

Underline expands from center outward on hover — clean and modern.

How It Works

The ::after underline starts with width: 0; left: 50% — centered but invisible. On hover, width grows to 100% while left moves to 0%. Both properties transition simultaneously, creating the expand-from-center effect. Compare this to the underline-slide in Part 1, which expands from the left edge.

.hover-underline-grow {
  --hug-color: #3b82f6;
  --hug-thickness: 2px;
  --hug-speed: 0.3s;
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--hug-color);
  position: relative;
  display: inline-block;
  cursor: pointer;
  text-decoration: none;
}

.hover-underline-grow::after {
  content: '';
  position: absolute;
  bottom: -2px;
  left: 50%;
  width: 0;
  height: var(--hug-thickness);
  background: var(--hug-color);
  transition: width var(--hug-speed) ease, left var(--hug-speed) ease;
}

.hover-underline-grow:hover::after {
  width: 100%;
  left: 0;
}
<div class="hover-underline-grow">Hover this link</div>

Tip: For a shrink-to-center on un-hover, add width: 100%; left: 0 as the default and transition to width: 0; left: 50% on hover.


37. 3D Tilt

Element tilts in 3D perspective on hover — creates depth and interactivity.

How It Works

The element has perspective: 500px and transform-style: preserve-3d to enable 3D space. On hover, rotateY(-10deg) rotateX(5deg) tilts the card in two axes simultaneously, creating a natural perspective shift. The gradient background (linear-gradient(135deg, #667eea, #764ba2)) enhances the 3D illusion by showing different color intensities at different angles.

.hover-3d-tilt {
  --h3dt-speed: 0.4s;
  width: 140px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: #ffffff;
  background: linear-gradient(135deg, #667eea, #764ba2);
  border-radius: 12px;
  cursor: pointer;
  transition: transform var(--h3dt-speed) ease;
  transform-style: preserve-3d;
  perspective: 500px;
}

.hover-3d-tilt:hover {
  transform: perspective(500px) rotateY(-10deg) rotateX(5deg);
}
<div class="hover-3d-tilt">Tilt Me</div>

Tip: For a mouse-tracking tilt effect, combine this with JavaScript that maps cursor position to rotation angles. Pure CSS gives a fixed tilt; JS makes it dynamic.


38. Sweep

Diagonal light sweep on hover — a shiny reflection passing across the element.

How It Works

Similar to the shine-sweep from Part 1, but uses skewX(-20deg) on the light strip to create a diagonal angle. The ::after starts at left: -100% (off-screen left) and slides to left: 130% (off-screen right). The height: 200% and top: -50% ensure the diagonal strip covers the full element height.

.hover-sweep {
  --hsw-color: #ffffff;
  --hsw-speed: 0.6s;
  position: relative;
  width: 140px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: #ffffff;
  background: #1e293b;
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
}

.hover-sweep::after {
  content: '';
  position: absolute;
  top: -50%;
  left: -100%;
  width: 60%;
  height: 200%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.15), transparent);
  transform: skewX(-20deg);
  transition: left var(--hsw-speed) ease;
}

.hover-sweep:hover::after {
  left: 130%;
}
<div class="hover-sweep">Sweep</div>

Tip: Adjust skewX angle for different sweep diagonals. -25deg is more dramatic, -10deg is more subtle.


39. Shine Line

A glossy diagonal line sweeps across on hover — thinner and more focused than the sweep.

How It Works

This is a narrower, more intense version of the sweep. The light strip is only 50% wide with a rgba(255,255,255,0.3) opacity — creating a focused shine line rather than a broad sweep. The skewX(-25deg) creates a steeper diagonal. The result is a quick glossy flash rather than a broad reflection.

.hover-shine-line {
  --hsl-color: #1e293b;
  --hsl-shine: rgba(255,255,255,0.3);
  --hsl-speed: 0.6s;
  position: relative;
  width: 140px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: #ffffff;
  background: var(--hsl-color);
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
}

.hover-shine-line::after {
  content: '';
  position: absolute;
  top: -50%;
  left: -75%;
  width: 50%;
  height: 200%;
  background: linear-gradient(90deg, transparent, var(--hsl-shine), transparent);
  transform: skewX(-25deg);
  transition: left var(--hsl-speed) ease;
}

.hover-shine-line:hover::after {
  left: 125%;
}
<div class="hover-shine-line">Shine</div>

Tip: Increase the shine opacity to 0.5 for a more visible flash, or decrease to 0.15 for subtle elegance.


40. Expand Border

Border expands from center outward on hover — animated outline reveal.

How It Works

A ::before pseudo-element creates a border using inset: 0 and border: 2px solid. It starts at scaleX(0) — compressed to zero width. On hover, it scales to scaleX(1) — expanding horizontally. The border appears to grow from the center because scaleX scales from the center by default.

.hover-expand-border {
  --heb-color: #8b5cf6;
  --heb-speed: 0.4s;
  position: relative;
  width: 120px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--heb-color);
  cursor: pointer;
}

.hover-expand-border::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 2px solid var(--heb-color);
  border-radius: 10px;
  transform: scaleX(0);
  transition: transform var(--heb-speed) ease;
}

.hover-expand-border:hover::before {
  transform: scaleX(1);
}
<div class="hover-expand-border">Expand</div>

Tip: Use scaleY(0)scaleY(1) for vertical expansion, or scale(0)scale(1) for both axes at once.


41. Backdrop

Background fades in behind the element on hover — soft and minimal.

How It Works

The simplest effect in this post — just a background and color transition. On hover, a semi-transparent blue background (rgba(59, 130, 246, 0.15)) fades in, and the text color shifts to match. No pseudo-elements, no transforms. It’s the hover equivalent of a soft highlight.

.hover-backdrop {
  --hbd-color: rgba(59, 130, 246, 0.15);
  --hbd-speed: 0.3s;
  padding: 12px 24px;
  border-radius: 8px;
  font-size: 0.9rem;
  font-weight: 600;
  color: #334155;
  cursor: pointer;
  transition: background var(--hbd-speed) ease, color var(--hbd-speed) ease;
}

.hover-backdrop:hover {
  background: var(--hbd-color);
  color: #3b82f6;
}
<div class="hover-backdrop">Hover for backdrop</div>

Tip: This works great on list items, table rows, or navigation items where you want subtle hover feedback without heavy animations.


42. Raise

Element lifts upward with a growing shadow — classic elevation effect.

How It Works

The inverse of sink — instead of pressing down, the element lifts up. translateY(-6px) raises it while box-shadow grows from a subtle 0 1px 3px to a dramatic 0 12px 20px. The shadow growth makes the lift feel physical — like the element is actually rising above the surface.

.hover-raise {
  --hra-color: #ffffff;
  --hra-speed: 0.3s;
  width: 140px;
  height: 80px;
  background: var(--hra-color);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: #334155;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  transition: transform var(--hra-speed) ease, box-shadow var(--hra-speed) ease;
}

.hover-raise:hover {
  transform: translateY(-6px);
  box-shadow: 0 12px 20px rgba(0,0,0,0.15);
}
<div class="hover-raise">Raise</div>

Tip: This is one of the most versatile hover effects. Use it on cards, buttons, and interactive elements of any kind.


43. Skew

Element skews horizontally on hover — dynamic angular distortion.

How It Works

A single transform: skewX(-8deg) on hover tilts the element horizontally. The negative value skews to the left; positive skews to the right. The effect is purely a shape distortion — no scaling or moving. Combined with the pink background, it creates an energetic, angular hover state.

.hover-skew {
  --hsk-color: #ec4899;
  --hsk-speed: 0.3s;
  width: 140px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: #ffffff;
  background: var(--hsk-color);
  border-radius: 8px;
  cursor: pointer;
  transition: transform var(--hsk-speed) ease;
}

.hover-skew:hover {
  transform: skewX(-8deg);
}
<div class="hover-skew">Skew Me</div>

Tip: Combine with scale(1.05) for a skew-zoom: transform: skewX(-8deg) scale(1.05).


44. Swap Icon

Icon flips on the Y-axis to reveal a different icon on hover — smooth icon transition.

How It Works

Same 3D flip technique as the flip-card, but in miniature. The outer container provides perspective: 200px. Inside, an inner wrapper uses transform-style: preserve-3d. Two faces sit back-to-back with backface-visibility: hidden. On hover, the inner wrapper rotates rotateY(180deg), hiding the front icon and revealing the back. In production, replace the + and - text with actual SVG icons or icon fonts.

.hover-swap-icon {
  --hsi-color: #1e293b;
  --hsi-speed: 0.4s;
  width: 50px;
  height: 50px;
  perspective: 200px;
  cursor: pointer;
}

.hover-swap-icon .hsi-inner {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  transition: transform var(--hsi-speed) ease;
}

.hover-swap-icon:hover .hsi-inner {
  transform: rotateY(180deg);
}

.hover-swap-icon .hsi-front,
.hover-swap-icon .hsi-back {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
  backface-visibility: hidden;
  color: var(--hsi-color);
}

.hover-swap-icon .hsi-back {
  transform: rotateY(180deg);
}
<div class="hover-swap-icon"><div class="hsi-inner"><div class="hsi-front">+</div><div class="hsi-back">-</div></div></div>

Tip: Replace text with emoji for quick prototyping: <div class="hsi-front">🔔</div><div class="hsi-back">🔕</div>.


What’s Next?

That completes all 24 hover effects from CSSKit — from simple underlines to 3D flips. Next up: loading animations — spinning rings, morphing shapes, skeleton loaders, and more.

Explore all 310 animations live at CSSKit or star the repo on GitHub.

You might also like

Enjoyed This Post?

Want to discuss the topic, have questions, or looking to collaborate on something similar? Drop a comment below or reach out directly.

Discussion