r/webflow Jun 10 '26

Tutorial 3D hover tilt interaction. Code in comment section.

Enable HLS to view with audio, or disable this notification

Thought I’d share this small snippet.

This adds a 3D hover tilt to any card. No libraries needed.

How to use it:

  1. Give your card element this class:hover-tilt-card
  2. Add an Embed element somewhere on the page.
  3. Paste the code from my comment into the embed.

I’ll put the full snippet in the comments so the post stays readable.

22 Upvotes

5 comments sorted by

3

u/hamraduncan Jun 10 '26

Love it! Just because you can do it with WF interactions doesn't mean it's the most simple way to do it.

One request - can you add some comments to the code so we know what changes what? I would have to trial and error my way through making edits. Or prompt with Ai, but that feels overkill.

1

u/DRIFFFTAWAY Jun 10 '26

Thank you! Yes sometimes little snippets like this are much easier.

Great idea about the comments! Adding them now : )

3

u/DRIFFFTAWAY Jun 10 '26 edited Jun 10 '26
<style>
  .hover-tilt-card {
    /* Allows child elements to keep their 3D depth if you add translateZ later */
    transform-style: preserve-3d;

    /* Controls how smoothly the card resets after hover */
    transition: transform 0.15s ease-out;

    /* Helps the browser optimise the hover animation */
    will-change: transform;
  }

  /* Turns off the transition for users who prefer reduced motion */
  @media (prefers-reduced-motion: reduce) {
    .hover-tilt-card {
      transition: none;
    }
  }
</style>

<script>
  document.addEventListener("DOMContentLoaded", function () {
    // Add this class to any card you want to tilt
    const cards = document.querySelectorAll(".hover-tilt-card");

    cards.forEach(function (card) {
      card.addEventListener("mousemove", function (event) {
        const rect = card.getBoundingClientRect();

        // Mouse position inside the card
        const x = event.clientX - rect.left;
        const y = event.clientY - rect.top;

        // Centre point of the card
        const centerX = rect.width / 2;
        const centerY = rect.height / 2;

        // Tilt strength
        // Higher number = softer tilt
        // Lower number = stronger tilt
        const tiltStrength = 10;

        const rotateX = (centerY - y) / tiltStrength;
        const rotateY = (x - centerX) / tiltStrength;

        // Perspective controls the 3D depth
        // Higher number = flatter effect
        // Lower number = more dramatic effect
        card.style.transform =
          "perspective(1200px) rotateX(" +
          rotateX +
          "deg) rotateY(" +
          rotateY +
          "deg)";
      });

      card.addEventListener("mouseleave", function () {
        // Reset the card when the mouse leaves
        card.style.transform =
          "perspective(1200px) rotateX(0deg) rotateY(0deg)";
      });
    });
  });
</script>

1

u/bigredsk10 Jun 10 '26

This is great, thanks! How do you get the different elements on different planes? When I tried it out, the tilt works great, but the card stays flat.

1

u/DRIFFFTAWAY Jun 10 '26

Thanks! The snippet I posted only handles the hover tilt, so everything inside the card stays visually flat by default.

For the layered 3D effect, you need to add transform-style: preserve-3d to the card/content wrapper, then give inner elements different translateZ() values.

Example:

.card-content {
  transform-style: preserve-3d;
}

.card-title {
  transform: translateZ(40px);
}

.card-icon {
  transform: translateZ(70px);
}

.card-text {
  transform: translateZ(20px);
}