GODRICH
#css-animation#button#loader#transition#scroll#dashboard#ui#design-trends

9 Mouse Effects CSS Tricks You Can Copy-Paste

Mouse effects css tricks are small interactions that react to pointer moves, clicks, drags, or scrolls.

Auto-plays · click a tile to jump to its section · all nine in one zip

These nine aren't ranked by popularity — they follow the order a pointer actually meets them on a page: idle, then morphing over a link (01), pulled toward a button (02), sweeping a background mouse effect of light and tilt across cards (03 and 04), dragging the screen sideways (05), right-clicking for a menu (06), painting a selected sentence (07), filling a ring while reading down the page (08), and finally sweeping a grid of tiles (09). The same moves ported to a screen with no mouse sit in Mobile Touch Gestures, and turning the pointer trail into a drawing continues in Signature Pad JavaScript.

01Cursor shape morph

What you see in these cursor effects css demos

Hovering a link grows the small dot cursor into a blue ring with an arrow inside; leaving shrinks it back to a dot. pointermove repositions the dot, and pointerenter/pointerleave swap its shape.

Cursor shape morph
Open in a new tab

01 · Cursor shape morph — Measured area 3.019% · moving frames 16/23Original by GODRICH · SCSS and React ship in the zip · See the password

pointermove translatedata-cursor 속성pointer:coarse 터치 제외

Where to look in the code

area.addEventListener('pointermove', function (e) {
  var r = area.getBoundingClientRect();
  cursor.style.transform =
    'translate(' + (e.clientX - r.left) + 'px,' +
    (e.clientY - r.top) + 'px)';
});
link.addEventListener('pointerenter', function () {
  cursor.classList.add('is-link');
});
link.addEventListener('pointerleave', function () {
  cursor.classList.remove('is-link');
});

02Magnetic pull button

What happens on screen

Moving the cursor near the button pulls it slightly toward the pointer; moving away springs it back.

Magnetic pull button
Open in a new tab

02 · Magnetic pull button — Measured area 6.596% · moving frames 11/23Original by GODRICH · SCSS and React ship in the zip · See the password

pointermove 거리×계수transform: translatepointerleave 리셋

How to read the code

The distance from the hit zone's center is multiplied by a strength factor (0.4) to get the translate value.

zone.addEventListener('pointermove', function (e) {
  var r = zone.getBoundingClientRect();
  var dx = e.clientX - (r.left + r.width / 2);
  var dy = e.clientY - (r.top + r.height / 2);
  btn.style.transform =
    'translate(' + dx * 0.4 + 'px,' + dy * 0.4 + 'px)';
});
zone.addEventListener('pointerleave', function () {
  btn.style.transform = '';
});

03Spotlight card reveal

What moves

Moving the cursor over the card drags a circular light with it, brightening the dim text wherever the light passes. mix-blend-mode: soft-light blends the light into the background, and screen brightens the text underneath.

Spotlight card reveal
Open in a new tab

03 · Spotlight card reveal — Measured area 20.166% · moving frames 17/23Original by GODRICH · SCSS and React ship in the zip · See the password

mix-blend-mode: soft-lightpointermove translatehover:none 대체

What to change

card.addEventListener('pointermove', function (e) {
  var r = card.getBoundingClientRect();
  spot.style.transform =
    'translate(' + (e.clientX - r.left) + 'px,' +
    (e.clientY - r.top) + 'px)';
});
card.addEventListener('pointerleave', function () {
  spot.style.transform = '';
});

043D tilt card

What you see

The card tilts in 3D based on where the cursor sits over it, with a diagonal sheen sweeping alongside.

3D tilt card
Open in a new tab

04 · 3D tilt card — Measured area 3.769% · moving frames 17/23Original by GODRICH · SCSS and React ship in the zip · See the password

perspective + rotateX/rotateYbackground-position 스윕신뢰감 있는 밝은 톤

Where to look in the code

The pointer's position is turned into a 0–1 ratio, then into rotateX/rotateY angles.

wrap.addEventListener('pointermove', function (e) {
  var r = wrap.getBoundingClientRect();
  var px = (e.clientX - r.left) / r.width;
  var py = (e.clientY - r.top) / r.height;
  var rx = (0.5 - py) * 6 * 2;
  var ry = (px - 0.5) * 6 * 2;
  card.style.transform =
    'perspective(600px) rotateX(' + rx + 'deg) rotateY(' + ry + 'deg)';
});

05Drag-to-scroll gallery

What happens on screen

Dragging the tiles as if grabbing them scrolls the gallery sideways, and it stops the moment you release.

Drag-to-scroll gallery
Open in a new tab

05 · Drag-to-scroll gallery — Measured area 13.938% · moving frames 20/23Original by GODRICH · SCSS and React ship in the zip · See the password

scrollLeft 직접 조작overflow-x: auto 네이티브 터치cursor: grab/grabbing

How to read the code

This moves the real scrollLeft, not a transform, so touch scrolling stays native and unbroken.

vp.addEventListener('pointerdown', function (e) {
  dragging = true;
  startX = e.clientX;
  startScroll = vp.scrollLeft;
  vp.setPointerCapture(e.pointerId);
});
vp.addEventListener('pointermove', function (e) {
  if (!dragging) return;
  vp.scrollLeft = startScroll - (e.clientX - startX);
});

06Custom right-click menu

What moves

Right-clicking the area shows a copy, edit, and delete icon menu popping up at the click point instead of the browser's default menu.

Custom right-click menu
Open in a new tab

06 · Custom right-click menu — Measured area 13.451% · moving frames 11/23Original by GODRICH · SCSS and React ship in the zip · See the password

contextmenu preventDefault좌표 클램프Escape·바깥 클릭 닫기

What to change

The coordinates are clamped so the menu never spills past the area's edge.

pad.addEventListener('contextmenu', function (e) {
  e.preventDefault();
  var r = pad.getBoundingClientRect();
  var x = Math.min(e.clientX - r.left, r.width - 132);
  var y = Math.min(e.clientY - r.top, r.height - 112);
  menu.style.left = x + 'px';
  menu.style.top = y + 'px';
  pad.classList.add('is-open');
});

07Text-selection highlight color

What you see

Dragging to select text paints it with a chosen highlighter color instead of browser blue, and a copy badge appears above it.

Text-selection highlight color
Open in a new tab

07 · Text-selection highlight color — Measured area 2.017% · moving frames 15/23Original by GODRICH · SCSS and React ship in the zip · See the password

::selection 색 지정selectionchange 이벤트getBoundingClientRect 배지 위치

Where to look in the code

The color is one ::selection rule, and the badge position comes from selectionchange.

::selection {
  background: #ff9ebb;
  color: #17141a;
}
document.addEventListener('selectionchange', function () {
  var sel = window.getSelection();
  if (sel.isCollapsed) return;
  var r = sel.getRangeAt(0).getBoundingClientRect();
  badge.style.left = r.left + r.width / 2 + 'px';
  badge.style.top = r.top - 28 + 'px';
  badge.classList.add('is-shown');
});

08Scroll-progress cursor ring

What happens on screen

While scrolling inside, a small ring that follows the cursor fills up with progress, turning into a checkmark at the end.

Scroll-progress cursor ring
Open in a new tab

08 · Scroll-progress cursor ring — Measured area 3.108% · moving frames 22/23Original by GODRICH · SCSS and React ship in the zip · See the password

stroke-dashoffsetscrollTop/scrollHeight 비율pointermove translate

How to read the code

The ring's stroke-dashoffset shrinks by the scroll ratio.

box.addEventListener('scroll', function () {
  var max = box.scrollHeight - box.clientHeight;
  var pct = max > 0 ? box.scrollTop / max : 0;
  ring.style.setProperty('--dash', (94.2 * (1 - pct)).toFixed(1));
  box.classList.toggle('is-done', pct > 0.98);
});

09Hover caption reveal grid

What moves

Hovering a grid tile slides a white caption strip up from the bottom to reveal its label, and keyboard focus triggers the same reveal.

Hover caption reveal grid
Open in a new tab

09 · Hover caption reveal grid — Measured area 10.226% · moving frames 21/23Original by GODRICH · SCSS and React ship in the zip · See the password

:hover + :focus-visibletransform: translateYstagger animation-delay

What to change

No JS at all — just :hover and :focus-visible.

.hg-tile__cap {
  transform: translateY(100%);
  transition: transform .3s ease-out;
}
.hg-tile:hover .hg-tile__cap,
.hg-tile:focus-visible .hg-tile__cap { transform: translateY(0); }

Where do mouse effects css tricks break?

The first trap showed up in card 04, the 3D tilt. rotateX/rotateY only look tilted — they shouldn't force a layout recalc — but at a 320px width the rotated card's visible bounding box still counted toward the scroll area, and the page overflowed sideways. A 9-degree tilt still overflowed; only after dropping to 6 degrees and shrinking the card itself did the 320px render stop overflowing. The second trap was card 05, the drag gallery: faking a finger-drag with transform drifts out of sync with the real scroll position, so real dragging has to move scrollLeft directly. The third was card 06's right-click menu — without clamping the coordinates, the menu gets cut off past the pad's right or bottom edge.

Accessibility — when a custom cursor gets in the way

Cards 01, 03, and 08 follow the cursor itself, so every transition/animation on them turns off under prefers-reduced-motion: reduce. But the bigger issue isn't motion — it's the cursor itself. For low-vision users, or anyone using a switch or joystick instead of a trackpad, a small custom cursor can be harder to spot than the system one. Card 01's cursor dot disappears entirely under @media (hover: none), (pointer: coarse); card 08 swaps back to the system cursor there. Cards 02 and 04 have no separate cursor element to hide — they just drop the pointer-driven transition. Card 03 hides its spotlight too, but brightens the text so it stays readable without it. Card 05's drag gallery actually works better on touch, since native scrolling stays underneath it. Cards 06, 07, and 09 each pair their mouse-only gesture (right-click, drag-select, hover) with a keyboard or focus fallback (Escape, Tab, :focus-visible) so the same feature works without a mouse. Turning pointer coordinates into values that redraw the screen is the same skeleton that repeats from a single seed in CSS Background Pattern Generator. The password for all nine files is c5gmgmdf, and once unzipped the vanilla and react folders let you compare the same nine behaviors side by side.

FAQ

Can mouse effects css and css hover effects be done with CSS alone?

Some of them, yes. Item 07's selection color and item 09's hover-caption grid run on ::selection and :hover alone. The rest need to read pointer coordinates, clicks, or scroll position, so a few lines of vanilla JS are unavoidable. Tilting a whole scene toward the cursor, angle math included, is unpacked in 3D Hover Effect CSS.

Does a custom cursor slow the page down?

Changing only transform on every pointermove skips layout recalculation, so it stays smooth on most pages. Still, cache getBoundingClientRect once for elements that don't resize instead of re-measuring it on every event.

Do these effects work on mobile?

Items 01, 02, 03, 04, and 08 assume a pointer, so they're hidden or given a fallback state in CSS on touch. Item 05's drag gallery and items 06, 07, and 09 were built to work naturally on touch as well.

Sources: MDN Pointer events, MDN prefers-reduced-motion · More: About, Hover interactions, Landing-page interactions

Enter the archive password

The password is inside this article. You will find it as you read.