22 CSS Transition Effects 20 / 22
Magnetic Button Effect
Buttons, icon links, nav items and FABs that translate toward the cursor within a 120px radius using mousemove vector math and spring easing.
This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.
The code
<div class="page">
<h1>Magnetic Button Effect</h1>
<p class="subtitle">Move your cursor near the buttons — they'll pull toward it</p>
<p class="hint">↓ hover to activate magnetism</p>
<!-- 1. CTA buttons -->
<section>
<h2>Call-to-Action Buttons</h2>
<div class="cta-row">
<div class="mag-wrap" data-strength="0.4">
<button class="btn-mag btn-solid"><span class="label">Get Started</span></button>
</div>
<div class="mag-wrap" data-strength="0.4">
<button class="btn-mag btn-purple"><span class="label">Upgrade Plan</span></button>
</div>
<div class="mag-wrap" data-strength="0.4">
<button class="btn-mag btn-outline"><span class="label">Learn More</span></button>
</div>
</div>
</section>
<!-- 2. Icon buttons -->
<section>
<h2>Social / Icon Buttons</h2>
<div class="icon-row">
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-dark"><span class="label">🌐</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-blue"><span class="label">𝕏</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-insta"><span class="label">📸</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-gh"><span class="label">🐙</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-li"><span class="label">in</span></button>
</div>
</div>
</section>
<!-- 3. Nav -->
<section>
<h2>Navigation Items</h2>
<nav class="nav-mag">
<div class="mag-wrap" data-strength="0.25"><button class="nav-item active">Home</button></div>
<div class="mag-wrap" data-strength="0.25"><button class="nav-item">Work</button></div>
<div class="mag-wrap" data-strength="0.25"><button class="nav-item">About</button></div>
<div class="mag-wrap" data-strength="0.25"><button class="nav-item">Blog</button></div>
<div class="mag-wrap" data-strength="0.25"><button class="nav-item">Contact</button></div>
</nav>
</section>
<!-- 4. FABs -->
<section>
<h2>Floating Action Buttons</h2>
<div class="fab-cluster">
<div class="mag-wrap" data-strength="0.45">
<button class="btn-mag fab fab-primary"><span class="label">✚ New Project</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon fab fab-sm"><span class="label">🔍</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon fab fab-sm"><span class="label">⚙️</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon fab fab-sm"><span class="label">📤</span></button>
</div>
</div>
</section>
</div> <div class="page">
<h1>Magnetic Button Effect</h1>
<p class="subtitle">Move your cursor near the buttons — they'll pull toward it</p>
<p class="hint">↓ hover to activate magnetism</p>
<!-- 1. CTA buttons -->
<section>
<h2>Call-to-Action Buttons</h2>
<div class="cta-row">
<div class="mag-wrap" data-strength="0.4">
<button class="btn-mag btn-solid"><span class="label">Get Started</span></button>
</div>
<div class="mag-wrap" data-strength="0.4">
<button class="btn-mag btn-purple"><span class="label">Upgrade Plan</span></button>
</div>
<div class="mag-wrap" data-strength="0.4">
<button class="btn-mag btn-outline"><span class="label">Learn More</span></button>
</div>
</div>
</section>
<!-- 2. Icon buttons -->
<section>
<h2>Social / Icon Buttons</h2>
<div class="icon-row">
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-dark"><span class="label">🌐</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-blue"><span class="label">𝕏</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-insta"><span class="label">📸</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-gh"><span class="label">🐙</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon bi-li"><span class="label">in</span></button>
</div>
</div>
</section>
<!-- 3. Nav -->
<section>
<h2>Navigation Items</h2>
<nav class="nav-mag">
<div class="mag-wrap" data-strength="0.25"><button class="nav-item active">Home</button></div>
<div class="mag-wrap" data-strength="0.25"><button class="nav-item">Work</button></div>
<div class="mag-wrap" data-strength="0.25"><button class="nav-item">About</button></div>
<div class="mag-wrap" data-strength="0.25"><button class="nav-item">Blog</button></div>
<div class="mag-wrap" data-strength="0.25"><button class="nav-item">Contact</button></div>
</nav>
</section>
<!-- 4. FABs -->
<section>
<h2>Floating Action Buttons</h2>
<div class="fab-cluster">
<div class="mag-wrap" data-strength="0.45">
<button class="btn-mag fab fab-primary"><span class="label">✚ New Project</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon fab fab-sm"><span class="label">🔍</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon fab fab-sm"><span class="label">⚙️</span></button>
</div>
<div class="mag-wrap" data-strength="0.5">
<button class="btn-icon fab fab-sm"><span class="label">📤</span></button>
</div>
</div>
</section>
</div>* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', sans-serif; background: #09090f; min-height: 100vh; overflow-x: hidden; }
.page { padding: 70px 40px; max-width: 1000px; margin: 0 auto; }
h1 { color: #fff; text-align: center; font-size: 2rem; margin-bottom: 8px; }
.subtitle { color: rgba(255,255,255,.4); text-align: center; margin-bottom: 50px; }
section { margin-bottom: 70px; }
section > h2 { color: rgba(255,255,255,.35); font-size: .72rem; text-transform: uppercase; letter-spacing: 3px; margin-bottom: 28px; }
/* Shared magnetic wrapper */
.mag-wrap {
display: inline-flex; position: relative;
/* JS will translate this on mousemove */
transition: transform .15s cubic-bezier(.25,.46,.45,.94);
}
/* ─────────────────────────────────────
1. Primary call-to-action buttons
───────────────────────────────────── */
.cta-row { display: flex; flex-wrap: wrap; gap: 28px; align-items: center; }
.btn-mag {
position: relative; overflow: hidden;
padding: 16px 40px; border-radius: 50px; border: none; cursor: pointer;
font-size: 1rem; font-weight: 700; letter-spacing: .5px;
transition: transform .15s cubic-bezier(.25,.46,.45,.94), box-shadow .25s;
}
/* Inner text span — also shifts slightly */
.btn-mag .label {
position: relative; z-index: 1; pointer-events: none;
display: block; transition: transform .15s cubic-bezier(.25,.46,.45,.94);
}
.btn-solid {
background: #fff; color: #09090f;
box-shadow: 0 4px 24px rgba(255,255,255,.1);
}
.btn-solid:hover { box-shadow: 0 8px 40px rgba(255,255,255,.25); }
.btn-purple {
background: linear-gradient(135deg, #7c3aed, #4f46e5); color: #fff;
box-shadow: 0 4px 24px rgba(124,58,237,.2);
}
.btn-purple:hover { box-shadow: 0 8px 40px rgba(124,58,237,.5); }
.btn-outline {
background: transparent; color: #fff;
border: 1.5px solid rgba(255,255,255,.3);
box-shadow: none;
}
.btn-outline:hover { border-color: rgba(255,255,255,.8); box-shadow: 0 0 32px rgba(255,255,255,.1); }
/* Ripple on click */
.btn-mag .ripple-burst {
position: absolute; border-radius: 50%;
background: rgba(255,255,255,.3); pointer-events: none;
transform: scale(0); animation: burst .55s ease-out forwards;
}
@keyframes burst {
to { transform: scale(3); opacity: 0; }
}
/* ─────────────────────────────────────
2. Icon / social buttons
───────────────────────────────────── */
.icon-row { display: flex; flex-wrap: wrap; gap: 20px; align-items: center; }
.btn-icon {
width: 56px; height: 56px; border-radius: 50%; border: none; cursor: pointer;
display: flex; align-items: center; justify-content: center; font-size: 1.3rem;
transition: transform .15s cubic-bezier(.25,.46,.45,.94), box-shadow .25s;
}
.btn-icon .label { display: flex; align-items: center; justify-content: center; }
.bi-dark { background: #1a1a2e; border: 1px solid rgba(255,255,255,.1); color: #fff; }
.bi-dark:hover { box-shadow: 0 8px 30px rgba(0,0,0,.6); }
.bi-blue { background: #1d9bf0; color: #fff; }
.bi-blue:hover { box-shadow: 0 8px 30px rgba(29,155,240,.4); }
.bi-insta { background: linear-gradient(135deg,#f09433,#e6683c,#dc2743,#cc2366,#bc1888); color: #fff; }
.bi-insta:hover { box-shadow: 0 8px 30px rgba(220,39,67,.4); }
.bi-gh { background: #24292f; color: #fff; border: 1px solid rgba(255,255,255,.1); }
.bi-gh:hover { box-shadow: 0 8px 30px rgba(0,0,0,.6); }
.bi-li { background: #0077b5; color: #fff; }
.bi-li:hover { box-shadow: 0 8px 30px rgba(0,119,181,.4); }
/* ─────────────────────────────────────
3. Nav links
───────────────────────────────────── */
.nav-mag {
display: flex; gap: 0; align-items: center;
background: rgba(255,255,255,.04); border-radius: 16px; padding: 6px;
border: 1px solid rgba(255,255,255,.08); width: fit-content;
}
.nav-item {
padding: 10px 22px; border-radius: 10px; border: none; cursor: pointer;
background: transparent; color: rgba(255,255,255,.6); font-size: .875rem; font-weight: 500;
transition: background .2s, color .2s, transform .15s cubic-bezier(.25,.46,.45,.94);
position: relative;
}
.nav-item.active { background: rgba(255,255,255,.1); color: #fff; }
/* ─────────────────────────────────────
4. Floating action cluster
───────────────────────────────────── */
.fab-cluster { display: flex; gap: 16px; align-items: center; }
.fab {
border-radius: 18px; border: none; cursor: pointer;
display: flex; align-items: center; gap: 10px;
font-size: .9rem; font-weight: 600; color: #fff;
transition: transform .15s cubic-bezier(.25,.46,.45,.94), box-shadow .25s;
}
.fab-primary { padding: 14px 28px; background: linear-gradient(135deg,#10b981,#059669); }
.fab-primary:hover { box-shadow: 0 10px 40px rgba(16,185,129,.4); }
.fab-sm { width: 48px; height: 48px; border-radius: 14px; padding: 0; justify-content: center; background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.12); font-size: 1.1rem; }
.fab-sm:hover { background: rgba(255,255,255,.14); }
/* ─── Cursor hint ─── */
.hint { color: rgba(255,255,255,.2); font-size: .8rem; text-align: center; margin-top: -30px; margin-bottom: 50px; } * { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', sans-serif; background: #09090f; min-height: 100vh; overflow-x: hidden; }
.page { padding: 70px 40px; max-width: 1000px; margin: 0 auto; }
h1 { color: #fff; text-align: center; font-size: 2rem; margin-bottom: 8px; }
.subtitle { color: rgba(255,255,255,.4); text-align: center; margin-bottom: 50px; }
section { margin-bottom: 70px; }
section > h2 { color: rgba(255,255,255,.35); font-size: .72rem; text-transform: uppercase; letter-spacing: 3px; margin-bottom: 28px; }
/* Shared magnetic wrapper */
.mag-wrap {
display: inline-flex; position: relative;
/* JS will translate this on mousemove */
transition: transform .15s cubic-bezier(.25,.46,.45,.94);
}
/* ─────────────────────────────────────
1. Primary call-to-action buttons
───────────────────────────────────── */
.cta-row { display: flex; flex-wrap: wrap; gap: 28px; align-items: center; }
.btn-mag {
position: relative; overflow: hidden;
padding: 16px 40px; border-radius: 50px; border: none; cursor: pointer;
font-size: 1rem; font-weight: 700; letter-spacing: .5px;
transition: transform .15s cubic-bezier(.25,.46,.45,.94), box-shadow .25s;
}
/* Inner text span — also shifts slightly */
.btn-mag .label {
position: relative; z-index: 1; pointer-events: none;
display: block; transition: transform .15s cubic-bezier(.25,.46,.45,.94);
}
.btn-solid {
background: #fff; color: #09090f;
box-shadow: 0 4px 24px rgba(255,255,255,.1);
}
.btn-solid:hover { box-shadow: 0 8px 40px rgba(255,255,255,.25); }
.btn-purple {
background: linear-gradient(135deg, #7c3aed, #4f46e5); color: #fff;
box-shadow: 0 4px 24px rgba(124,58,237,.2);
}
.btn-purple:hover { box-shadow: 0 8px 40px rgba(124,58,237,.5); }
.btn-outline {
background: transparent; color: #fff;
border: 1.5px solid rgba(255,255,255,.3);
box-shadow: none;
}
.btn-outline:hover { border-color: rgba(255,255,255,.8); box-shadow: 0 0 32px rgba(255,255,255,.1); }
/* Ripple on click */
.btn-mag .ripple-burst {
position: absolute; border-radius: 50%;
background: rgba(255,255,255,.3); pointer-events: none;
transform: scale(0); animation: burst .55s ease-out forwards;
}
@keyframes burst {
to { transform: scale(3); opacity: 0; }
}
/* ─────────────────────────────────────
2. Icon / social buttons
───────────────────────────────────── */
.icon-row { display: flex; flex-wrap: wrap; gap: 20px; align-items: center; }
.btn-icon {
width: 56px; height: 56px; border-radius: 50%; border: none; cursor: pointer;
display: flex; align-items: center; justify-content: center; font-size: 1.3rem;
transition: transform .15s cubic-bezier(.25,.46,.45,.94), box-shadow .25s;
}
.btn-icon .label { display: flex; align-items: center; justify-content: center; }
.bi-dark { background: #1a1a2e; border: 1px solid rgba(255,255,255,.1); color: #fff; }
.bi-dark:hover { box-shadow: 0 8px 30px rgba(0,0,0,.6); }
.bi-blue { background: #1d9bf0; color: #fff; }
.bi-blue:hover { box-shadow: 0 8px 30px rgba(29,155,240,.4); }
.bi-insta { background: linear-gradient(135deg,#f09433,#e6683c,#dc2743,#cc2366,#bc1888); color: #fff; }
.bi-insta:hover { box-shadow: 0 8px 30px rgba(220,39,67,.4); }
.bi-gh { background: #24292f; color: #fff; border: 1px solid rgba(255,255,255,.1); }
.bi-gh:hover { box-shadow: 0 8px 30px rgba(0,0,0,.6); }
.bi-li { background: #0077b5; color: #fff; }
.bi-li:hover { box-shadow: 0 8px 30px rgba(0,119,181,.4); }
/* ─────────────────────────────────────
3. Nav links
───────────────────────────────────── */
.nav-mag {
display: flex; gap: 0; align-items: center;
background: rgba(255,255,255,.04); border-radius: 16px; padding: 6px;
border: 1px solid rgba(255,255,255,.08); width: fit-content;
}
.nav-item {
padding: 10px 22px; border-radius: 10px; border: none; cursor: pointer;
background: transparent; color: rgba(255,255,255,.6); font-size: .875rem; font-weight: 500;
transition: background .2s, color .2s, transform .15s cubic-bezier(.25,.46,.45,.94);
position: relative;
}
.nav-item.active { background: rgba(255,255,255,.1); color: #fff; }
/* ─────────────────────────────────────
4. Floating action cluster
───────────────────────────────────── */
.fab-cluster { display: flex; gap: 16px; align-items: center; }
.fab {
border-radius: 18px; border: none; cursor: pointer;
display: flex; align-items: center; gap: 10px;
font-size: .9rem; font-weight: 600; color: #fff;
transition: transform .15s cubic-bezier(.25,.46,.45,.94), box-shadow .25s;
}
.fab-primary { padding: 14px 28px; background: linear-gradient(135deg,#10b981,#059669); }
.fab-primary:hover { box-shadow: 0 10px 40px rgba(16,185,129,.4); }
.fab-sm { width: 48px; height: 48px; border-radius: 14px; padding: 0; justify-content: center; background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.12); font-size: 1.1rem; }
.fab-sm:hover { background: rgba(255,255,255,.14); }
/* ─── Cursor hint ─── */
.hint { color: rgba(255,255,255,.2); font-size: .8rem; text-align: center; margin-top: -30px; margin-bottom: 50px; }const RADIUS = 120; // activation radius in px
document.querySelectorAll('.mag-wrap').forEach(wrap => {
const strength = parseFloat(wrap.dataset.strength) || 0.4;
const btn = wrap.querySelector('button');
const label = btn.querySelector('.label');
wrap.addEventListener('mousemove', e => {
const r = wrap.getBoundingClientRect();
const cx = r.left + r.width / 2;
const cy = r.top + r.height / 2;
const dx = e.clientX - cx;
const dy = e.clientY - cy;
const dist = Math.hypot(dx, dy);
if (dist < RADIUS) {
const factor = (1 - dist / RADIUS) * strength;
const tx = dx * factor;
const ty = dy * factor;
wrap.style.transform = `translate(${tx}px, ${ty}px)`;
if (label) label.style.transform = `translate(${tx * .4}px, ${ty * .4}px)`;
btn.style.transform = '';
}
});
wrap.addEventListener('mouseleave', () => {
wrap.style.transform = '';
if (label) label.style.transform = '';
});
// Ripple on click
btn.addEventListener('click', e => {
const r = btn.getBoundingClientRect();
const x = e.clientX - r.left;
const y = e.clientY - r.top;
const span = document.createElement('span');
span.className = 'ripple-burst';
const s = Math.max(r.width, r.height);
span.style.cssText = `width:${s}px;height:${s}px;left:${x - s/2}px;top:${y - s/2}px`;
btn.appendChild(span);
setTimeout(() => span.remove(), 600);
});
});
// Nav active state
document.querySelectorAll('.nav-item').forEach(b => {
b.addEventListener('click', () => {
document.querySelectorAll('.nav-item').forEach(x => x.classList.remove('active'));
b.classList.add('active');
});
}); const RADIUS = 120; // activation radius in px
document.querySelectorAll('.mag-wrap').forEach(wrap => {
const strength = parseFloat(wrap.dataset.strength) || 0.4;
const btn = wrap.querySelector('button');
const label = btn.querySelector('.label');
wrap.addEventListener('mousemove', e => {
const r = wrap.getBoundingClientRect();
const cx = r.left + r.width / 2;
const cy = r.top + r.height / 2;
const dx = e.clientX - cx;
const dy = e.clientY - cy;
const dist = Math.hypot(dx, dy);
if (dist < RADIUS) {
const factor = (1 - dist / RADIUS) * strength;
const tx = dx * factor;
const ty = dy * factor;
wrap.style.transform = `translate(${tx}px, ${ty}px)`;
if (label) label.style.transform = `translate(${tx * .4}px, ${ty * .4}px)`;
btn.style.transform = '';
}
});
wrap.addEventListener('mouseleave', () => {
wrap.style.transform = '';
if (label) label.style.transform = '';
});
// Ripple on click
btn.addEventListener('click', e => {
const r = btn.getBoundingClientRect();
const x = e.clientX - r.left;
const y = e.clientY - r.top;
const span = document.createElement('span');
span.className = 'ripple-burst';
const s = Math.max(r.width, r.height);
span.style.cssText = `width:${s}px;height:${s}px;left:${x - s/2}px;top:${y - s/2}px`;
btn.appendChild(span);
setTimeout(() => span.remove(), 600);
});
});
// Nav active state
document.querySelectorAll('.nav-item').forEach(b => {
b.addEventListener('click', () => {
document.querySelectorAll('.nav-item').forEach(x => x.classList.remove('active'));
b.classList.add('active');
});
});More from 22 CSS Transition Effects
Card Tilt 3D HoverStaggered List AnimationCursor Trail EffectSplit Text Reveal TransitionProgress Bar AnimationButton Hover TransitionsFlip Card 3D TransitionText Reveal AnimationImage Zoom Hover TransitionBackground Color TransitionBorder Animation TransitionNavigation Hover Transition
View the full collection →