webdevpuneet.com

3D Card Tilt — Free HTML CSS JS Hover Snippet

3D Card Tilt · Animations · Plain HTML, CSS & JS · Live preview

CategoryAnimations

Copy & paste

Source Code

<div class="scene">
  <div class="card" id="card">
    <div class="glow" id="glow"></div>
    <div class="tag">⭐ Featured</div>
    <h3>3D Tilt Card</h3>
    <p>Move your mouse over this card to see the 3D perspective tilt effect with a dynamic highlight.</p>
    <div class="footer">
      <div class="avatars">
        <span class="av" style="background:#6366f1">A</span>
        <span class="av" style="background:#8b5cf6">B</span>
        <span class="av" style="background:#ec4899">C</span>
      </div>
      <button class="cta">View project →</button>
    </div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

perspective: 800px on .scene — establishes 3D viewing context
rotX = -(dy / height) * 20, rotY = (dx / width) * 20 — normalised tilt angles
mousemove updates card transform: rotateX(rotX) rotateY(rotY) scale(1.02)
.glow div tracks cursor position: absolute element with filter blur
mouseleave resets card to identity transform and glow to centre
transition: transform 0.1s ease — smooth snap-back on leave
transform-style: preserve-3d on card for child 3D positioning
Export as HTML file, React JSX, or React + Tailwind CSS
Mobile (375px), Tablet (768px), Desktop device preview buttons
Live split-pane editor — preview updates as you type

About this UI Snippet

3D Card Tilt — rotateX/Y from Mouse Offset, Glow Follow & Perspective Context

Screenshot of the 3D Card Tilt snippet rendered live

The 3D card tilt effect gives cards a physical presence — they rotate in perspective to face the cursor as the mouse moves over them, creating the illusion of a real object responding to light and viewpoint. Used on premium product cards, portfolio thumbnails, and feature showcases — for a flip-to-reveal interaction instead, see the 3D flip card.

The rotation calculation

The mousemove handler uses getBoundingClientRect() to get the card centre (cx, cy). The offsets dx = e.clientX - cx and dy = e.clientY - cy are normalised by card dimensions: rotX = -(dy / rect.height) * 20 and rotY = (dx / rect.width) * 20. This maps mouse position across the card surface to ±20 degrees of rotation. The negative on rotX flips the Y axis — moving the cursor up tilts the top of the card toward you.

The perspective context

.scene { perspective: 800px } establishes the 3D viewing context. 800px is the distance from the viewer to the card — lower values give more dramatic perspective foreshortening. The card has transform-style: preserve-3d so child elements can optionally be positioned in the same 3D space.

The following glow

A .glow div inside the card uses position: absolute; filter: blur() to create a light source. Its position is updated in the mousemove handler: glow.style.left and glow.style.top track the cursor position relative to the card, creating a highlight that follows the cursor.

mouseleave reset

On mouseleave, the card is reset to transform: rotateX(0) rotateY(0) scale(1) and the glow returns to centre. The CSS transition: transform 0.1s ease handles the snap-back smoothly.

The perspective transform calculation

On mousemove inside the card, the handler computes the cursor position relative to the card centre: const centerX = rect.left + rect.width/2; const centerY = rect.top + rect.height/2; const rotX = -(e.clientY - centerY) / (rect.height/2) * 10; const rotY = (e.clientX - centerX) / (rect.width/2) * 10. The division by half the card dimension normalises to a -1 to +1 range; multiplying by 10 gives a maximum 10-degree rotation. Negative rotX is needed because moving the cursor up should tilt the top of the card toward the viewer.

The glow highlight

A radial gradient overlay follows the cursor inside the card: background: radial-gradient(circle at X Y, rgba(255,255,255,0.15), transparent 70%). The X and Y values are the cursor position as a percentage of the card dimensions: ((e.clientX - rect.left) / rect.width * 100) + '% ' + ((e.clientY - rect.top) / rect.height * 100) + '%'. This creates a specular highlight that appears to move with the cursor, reinforcing the 3D illusion.

Reset on mouse leave

On mouseleave, rotX and rotY are reset to 0 with transition: transform 0.5s ease — a slower ease-out that lets the card settle back to flat gently, like a physical object returning to rest.

Step by step

How to Use

  1. 1
    Move the cursor over the cardSlowly move the cursor across the card in the preview to see the 3D perspective tilt and the glow following the cursor.
  2. 2
    Change the tilt intensityIn the JS panel, update the * 20 multiplier on rotX and rotY calculations. Higher values create more dramatic tilt.
  3. 3
    Change the perspective distanceUpdate perspective: 800px on .scene in the CSS panel. Lower values (400px) give more dramatic 3D; higher (1200px) give subtler tilt.
  4. 4
    Update card contentIn the HTML panel, update the badge, heading, and description text inside .card.
  5. 5
    Disable the glowRemove the .glow element from the HTML and the glow.style lines from the JS panel for a cleaner tilt without the light effect.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

Premium product and feature cards
Apply to product feature cards on a landing page. The tilt gives each card physical depth and makes the interface feel crafted rather than flat.
Portfolio project thumbnails
Use on project cards in a portfolio grid. The 3D tilt on hover makes each project feel interactive before the user even clicks.
Learn rotateX/Y normalisation math
The rotation formula divides cursor offset by card dimension to normalise to a ±1 range before multiplying by the max angle. Edit the multiplier in the JS panel to understand the relationship.
Pricing and plan cards
Add tilt to pricing cards to make them feel more interactive. The Featured card with an extra glow effect naturally draws attention.
NFT and collectible card displays
The 3D tilt is the standard interaction for NFT card galleries. The perspective and glow simulate a physical collectible card being held under light.
Apply to any card element
Copy the mousemove, mouseleave listeners and the .glow CSS onto any card. Add perspective to the parent wrapper and preserve-3d to the card.
Related: AI Code Typing Preview
See the AI Code Typing Preview for a related animations pattern worth pairing with this one.
Related: 3D Swipe Card Stack
See the 3D Swipe Card Stack for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

getBoundingClientRect gives the card position. dx = e.clientX - cx gives horizontal offset from centre (-width/2 to +width/2). Dividing by rect.height normalises to -0.5 to +0.5. Multiplying by 20 gives -10 to +10 degrees of tilt. The negative on rotX flips the Y axis.

perspective: 800px sets the virtual distance from the viewer to the card in pixels. Lower values (300-500px) create more dramatic foreshortening — the card appears to recede sharply. Higher values (1200px+) give subtle, realistic depth. The perspective property must be on the parent, not the card itself.

The .glow element is positioned absolutely inside the card. In mousemove, glow.style.left and glow.style.top are set to (e.clientX - rect.left) and (e.clientY - rect.top) — the cursor position relative to the card top-left corner.

Delete the <div class="glow"> from the HTML and remove all glow.style lines from the JS. The tilt works independently of the glow element.

Yes. Instead of targeting one element by ID, use querySelectorAll(".card") and addEventListener("mousemove") on each. Move the handler logic to a shared function that receives the card and glow elements as parameters.

Yes. Click "JSX" for a React component. In React, attach onMouseMove and onMouseLeave to the card div. Use useRef to access the card and glow elements directly to set style without state updates (avoiding rerenders on every mouse move).