Interactive UI elements are a great way to add personality and polish to your web projects. In this tutorial, we’ll explore how to create 3D Tilt Food Cards that respond to your mouse movements, giving users a delightful and engaging experience. Perfect for restaurant menus, food blogs, or portfolio demos!
🌐 What We’ll Build
We’re designing a set of food item cards — think of pasta, salad, and pizza — that react to your cursor with a cool 3D tilt animation. The card slightly rotates based on your mouse position, making it feel like it’s popping out of the screen.
🔧 Technologies Used
-
HTML – To create the structure of the cards
-
CSS – For styling and 3D effects
-
JavaScript – To handle the tilt interaction
HTML Structure:
Each food item is wrapped inside a .card
div. Here’s what each card includes:
-
An image of the food item
-
A title (
h3
) -
A short description
-
A price tag
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>3D Tilt Food Cards</title> <!-- Google Font --> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;500;600&display=swap" rel="stylesheet" /> <!-- External CSS --> <link rel="stylesheet" href="style.css" /> </head> <body> <div class="card-container"> <div class="card"> <img src="pasta.png" alt="Pasta Primavera" /> <div class="content"> <h3 class="title">Pasta Primavera</h3> <p class="description"> Fresh pasta with seasonal vegetables and Parmesan </p> <p class="price">$12.99</p> </div> </div> <div class="card"> <img src="salad.png" alt="Caesar Salad" /> <div class="content"> <h3 class="title">Caesar Salad</h3> <p class="description"> Crisp lettuce, croutons and Caesar dressing </p> <p class="price">$7.99</p> </div> </div> <div class="card"> <img src="pizza-3.png" alt="Margherita Pizza" /> <div class="content"> <h3 class="title">Margherita Pizza</h3> <p class="description"> Classic pizza with mozzarella, tomatoes and basil </p> <p class="price">$9.99</p> </div> </div> </div> <!-- External JS --> <script src="script.js"></script> </body> </html>
CSS:
The magic starts with 3D perspective using
transform-style: preserve-3d
andperspective: 1500px
on the container. Here’s what the key styles do:-
Box Shadow & Rounded Corners: Adds depth and softness.
-
Hover Effect: Elevates the card on hover for a subtle effect.
-
Responsiveness: Media queries adapt card size for smaller screens.
* { box-sizing: border-box; padding: 0; margin: 0; } body { margin: 0; background-color: #f7f7f7; display: flex; height: 100vh; font-family: "Poppins", sans-serif; justify-content: center; align-items: center; flex-direction: column; } .card-container { display: flex; gap: 40px; perspective: 1500px; flex-wrap: wrap; justify-content: center; margin-top: 20px; } .card { position: relative; width: 250px; height: 400px; border-radius: 20px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); transition: transform 0.1s ease, box-shadow 0.2s ease; transform-style: preserve-3d; cursor: pointer; overflow: hidden; margin-bottom: 20px; background-color: #ffffff; padding: 30px; text-align: center; } .card::before { content: ""; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: radial-gradient( circle at center, rgba(255, 255, 255, 0.05), transparent ); pointer-events: none; transform: rotate(25deg); transition: opacity 0.2s ease; } .card img { width: 100%; height: 55%; top: 20px; object-fit: cover; position: relative; } .card .title { margin: 10px 0 0; } .card .description { font-size: 16px; color: #909090; margin: 0 0 15px 0; } .card .price { margin: 5px 0; font-size: 18px; color: #ff6247; } .card:hover { box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2); } @media (max-width: 768px) { .card { width: 300px; padding: 30px; } } @media (max-width: 480px) { .card-container { flex-direction: column; gap: 20px; } .card { width: 250px; height: auto; } }
JavaScript Tilt Effect
Here’s the heart of the interaction. Using
mousemove
, we calculate the cursor’s position relative to the center of the card and apply arotateX
androtateY
transformation accordingly.const cards = document.querySelectorAll(".card"); cards.forEach((card) => { card.addEventListener("mousemove", (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; const rotateX = (y - centerY) / 10; const rotateY = (x - centerX) / 10; card.style.transform = `rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(1.05)`; }); card.addEventListener("mouseleave", () => { card.style.transform = "rotateX(0deg) rotateY(0deg)"; }); });
-