About this snippet

Move your mouse over the card and it tilts to follow, with a band of light sweeping across the surface. Moving away settles it back to flat.

The tilt is a rotateX and rotateY pair worked out from how far the cursor sits from the card center, capped at 15 degrees each way. The parent holds the perspective value, and that is what makes the rotation read as depth instead of a flat skew. Card number, logos and labels each carry their own translateZ, so they float above the surface at different heights.

The sheen is a separate layer holding an oversized diagonal gradient. Only its background-position moves, which is far cheaper than redrawing a gradient, and mix-blend-mode overlay keeps it looking like reflected light rather than a white streak. Transitions are switched off on mouseenter so tracking stays instant, then switched back on for the settle.

Size
4.5 KB
Uses
HTML, CSS, JavaScript
Loads
Nothing external
Views
220
<div class="checkout-wrapper">
  <div class="card-perspective">
    <div class="credit-card" id="credit-card">
      <div class="hologram-layer" id="hologram"></div>
      
      <div class="card-inner">
        <div class="card-top">
          <svg viewBox="0 0 24 24" width="40" height="40" fill="none" stroke="#fbbf24" stroke-width="1.5"><rect x="2" y="5" width="20" height="14" rx="2" ry="2"></rect><line x1="2" y1="10" x2="22" y2="10"></line></svg>
          <svg viewBox="0 0 24 24" width="40" height="40" fill="#ffffff" opacity="0.8"><circle cx="8" cy="12" r="6"></circle><circle cx="16" cy="12" r="6"></circle></svg>
        </div>
        
        <div class="card-number">4000 1234 5678 9010</div>
        
        <div class="card-bottom">
          <div class="card-holder">
            <span class="label">Card Holder</span>
            <span class="value">ALEXANDER SMITH</span>
          </div>
          <div class="card-expires">
            <span class="label">Expires</span>
            <span class="value">12/28</span>
          </div>
        </div>
      </div>
    </div>
  </div>
  
  <p class="helper-text">Hover over the card to interact</p>
</div>
*, *::before, *::after {
  box-sizing: border-box;
}

body {
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  margin: 0;
  background: #e2e8f0;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

.checkout-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 30px;
}

.card-perspective {
  perspective: 1000px;
  width: 400px;
  height: 250px;
}

.credit-card {
  position: relative;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #1e293b, #0f172a);
  border-radius: 20px;
  box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.4), inset 0 1px 1px rgba(255, 255, 255, 0.2);
  transform-style: preserve-3d;
  will-change: transform;
  overflow: hidden;
  cursor: pointer;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.hologram-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(115deg, transparent 20%, rgba(255,255,255,0.3) 30%, transparent 40%);
  background-size: 300% 300%;
  background-position: 50% 50%;
  z-index: 2;
  mix-blend-mode: overlay;
  pointer-events: none;
}

.card-inner {
  position: relative;
  z-index: 3;
  padding: 30px;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #ffffff;
}

.card-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  transform: translateZ(30px);
}

.card-number {
  font-size: 1.43rem;
  font-family: "Courier New", Courier, monospace;
  letter-spacing: 4px;
  text-shadow: 0 2px 4px rgba(0,0,0,0.5);
  transform: translateZ(40px);
}

.card-bottom {
  display: flex;
  justify-content: space-between;
  transform: translateZ(20px);
}

.label {
  display: block;
  font-size: 0.65rem;
  color: #94a3b8;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-bottom: 4px;
}

.value {
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: 1px;
  text-shadow: 0 1px 2px rgba(0,0,0,0.5);
}

.helper-text {
  color: #64748b;
  font-weight: 500;
}
const card = document.getElementById("credit-card");
const hologram = document.getElementById("hologram");

card.addEventListener("mousemove", function(e) {
  const rect = card.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  
  const centerX = rect.width / 2;
  const centerY = rect.height / 2;
  
  /* Calculate rotation based on cursor distance from center */
  const rotateX = ((y - centerY) / centerY) * -15;
  const rotateY = ((x - centerX) / centerX) * 15;
  
  card.style.transform = "rotateX(" + rotateX + "deg) rotateY(" + rotateY + "deg)";
  
  /* Shift the gradient background for the holographic effect */
  const bgX = (x / rect.width) * 100;
  const bgY = (y / rect.height) * 100;
  hologram.style.backgroundPosition = bgX + "% " + bgY + "%";
});

card.addEventListener("mouseleave", function() {
  /* Snap back securely with a smooth transition */
  card.style.transition = "transform 0.5s ease";
  card.style.transform = "rotateX(0deg) rotateY(0deg)";
  hologram.style.transition = "background-position 0.5s ease";
  hologram.style.backgroundPosition = "50% 50%";
});

card.addEventListener("mouseenter", function() {
  /* Remove transition to allow instant mouse tracking */
  card.style.transition = "none";
  hologram.style.transition = "none";
});
Esc
↑↓ moveEnter select

Start from a template

Open an .html file, or HTML, CSS, JS, Markdown, Less or TypeScript files. You can also drop them here. Styles and scripts go into their panes.

Share

Source

Keyboard shortcuts

Save