24 / 30
All 30 in 30 Tailwind CSS Hover Effects
- 01Tailwind Underline Draw Hover Effect
- 02Tailwind Text Glitch Hover Effect
- 03Tailwind Letter Spacing Expand Hover Effect
- 04Tailwind Gradient Text Reveal Hover Effect
- 05Tailwind Split Text Hover Effect
- 06Tailwind Neon Glow Text Hover Effect
- 07Tailwind Magnetic Liquid Button Hover Effect
- 08Tailwind Border Draw Hover Effect
- 09Tailwind Shimmer Shine Button Hover Effect
- 10Tailwind Fill Wipe Button Hover Effect
- 11Tailwind 3D Press Button Hover Effect
- 12Tailwind Ripple Button Hover Effect
- 13Tailwind 3D Tilt Card Hover Effect
- 14Tailwind Card Flip Hover Effect
- 15Tailwind Glassmorphism Card Hover Effect
- 16Tailwind Spotlight Card Hover Effect
- 17Tailwind Slide Reveal Card Hover Effect
- 18Tailwind Stack Lift Card Hover Effect
- 19Tailwind Zoom Pan Image Hover Effect
- 20Tailwind Color Channel Split Hover Effect
- 21Tailwind Duotone Image Hover Effect
- 22Tailwind Curtain Reveal Image Hover Effect
- 23Tailwind Ken Burns Image Hover Effect
- 24Tailwind Image Tilt Depth Hover Effect
- 25Tailwind Underline Slide Nav Hover Effect
- 26Tailwind Highlight Fill Nav Hover Effect
- 27Tailwind Strikethrough Hover Link Effect
- 28Tailwind Inline Word Swap Hover Effect
- 29Tailwind Dot Trail Cursor Hover Effect
- 30Tailwind Magnetic Cursor Pull Hover Effect
Tailwind Image Tilt Depth Hover Effect
Four photo cards that lean in 3D, each with a conic specular sheen and a caption that rises on hover. The shadow direction is matched to the lean on every variant, which is what sells the depth.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="thv-24 w-full min-h-svh bg-thv24-bg font-thv24-sans px-8 py-12">
<p class="text-center text-[0.75rem] tracking-[0.14em] uppercase text-thv24-dim mb-10">Image Tilt Depth — 4 Variants</p>
<div class="flex flex-wrap justify-center items-start gap-10">
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[220px] aspect-[3/4] overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-y-[12deg] group-hover:rotate-x-[-6deg] group-hover:shadow-[-14px_18px_50px_rgba(0,0,0,.7)] group-focus-visible:rotate-y-[12deg] group-focus-visible:rotate-x-[-6deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:group-hover:rotate-x-0">
<img src="https://picsum.photos/seed/tilt1/300/400" alt="Portrait study in warm light" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Portrait Tilt</span>
</span>
</a>
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[320px] max-w-full aspect-video overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-x-[10deg] group-hover:rotate-y-[-5deg] group-hover:shadow-[0_-14px_40px_rgba(0,0,0,.6)] group-focus-visible:rotate-x-[10deg] group-focus-visible:rotate-y-[-5deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:rotate-y-0">
<img src="https://picsum.photos/seed/tilt2/400/260" alt="Wide landscape at golden hour" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Landscape Tilt</span>
</span>
</a>
<a href="#" class="group perspective-[500px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[220px] aspect-[3/4] overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-y-[-16deg] group-hover:rotate-x-[8deg] group-hover:shadow-[20px_14px_60px_rgba(0,0,0,.8)] group-focus-visible:rotate-y-[-16deg] group-focus-visible:rotate-x-[8deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:group-hover:rotate-x-0">
<img src="https://picsum.photos/seed/tilt3/300/400" alt="Architectural detail in shadow" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Deep Perspective</span>
</span>
</a>
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[320px] max-w-full aspect-video overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-x-[5deg] group-hover:rotate-y-[5deg] group-hover:translate-z-[12px] group-hover:shadow-[-8px_20px_50px_rgba(0,0,0,.65)] group-focus-visible:rotate-x-[5deg] group-focus-visible:rotate-y-[5deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:rotate-y-0">
<img src="https://picsum.photos/seed/tilt4/400/260" alt="Still life on a flat surface" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Flat Hover Lift</span>
</span>
</a>
</div>
</section><section class="thv-24 w-full min-h-svh bg-thv24-bg font-thv24-sans px-8 py-12">
<p class="text-center text-[0.75rem] tracking-[0.14em] uppercase text-thv24-dim mb-10">Image Tilt Depth — 4 Variants</p>
<div class="flex flex-wrap justify-center items-start gap-10">
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[220px] aspect-[3/4] overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-y-[12deg] group-hover:rotate-x-[-6deg] group-hover:shadow-[-14px_18px_50px_rgba(0,0,0,.7)] group-focus-visible:rotate-y-[12deg] group-focus-visible:rotate-x-[-6deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:group-hover:rotate-x-0">
<img src="https://picsum.photos/seed/tilt1/300/400" alt="Portrait study in warm light" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Portrait Tilt</span>
</span>
</a>
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[320px] max-w-full aspect-video overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-x-[10deg] group-hover:rotate-y-[-5deg] group-hover:shadow-[0_-14px_40px_rgba(0,0,0,.6)] group-focus-visible:rotate-x-[10deg] group-focus-visible:rotate-y-[-5deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:rotate-y-0">
<img src="https://picsum.photos/seed/tilt2/400/260" alt="Wide landscape at golden hour" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Landscape Tilt</span>
</span>
</a>
<a href="#" class="group perspective-[500px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[220px] aspect-[3/4] overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-y-[-16deg] group-hover:rotate-x-[8deg] group-hover:shadow-[20px_14px_60px_rgba(0,0,0,.8)] group-focus-visible:rotate-y-[-16deg] group-focus-visible:rotate-x-[8deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:group-hover:rotate-x-0">
<img src="https://picsum.photos/seed/tilt3/300/400" alt="Architectural detail in shadow" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Deep Perspective</span>
</span>
</a>
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[320px] max-w-full aspect-video overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-x-[5deg] group-hover:rotate-y-[5deg] group-hover:translate-z-[12px] group-hover:shadow-[-8px_20px_50px_rgba(0,0,0,.65)] group-focus-visible:rotate-x-[5deg] group-focus-visible:rotate-y-[5deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:rotate-y-0">
<img src="https://picsum.photos/seed/tilt4/400/260" alt="Still life on a flat surface" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Flat Hover Lift</span>
</span>
</a>
</div>
</section>@import "tailwindcss";
@theme {
--color-thv24-bg: #0e0e12;
--color-thv24-bg: oklch(0.15 0.01 285);
--color-thv24-dim: #94949e;
--color-thv24-dim: oklch(0.67 0.01 285);
--color-thv24-acc: #a78bfa;
--color-thv24-acc: oklch(0.72 0.15 295);
--font-thv24-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-24 {
width: 100%;
min-height: 100svh;
}
.thv-24 ::selection {
background: var(--color-thv24-acc);
color: #000;
}@import "tailwindcss";
@theme {
--color-thv24-bg: #0e0e12;
--color-thv24-bg: oklch(0.15 0.01 285);
--color-thv24-dim: #94949e;
--color-thv24-dim: oklch(0.67 0.01 285);
--color-thv24-acc: #a78bfa;
--color-thv24-acc: oklch(0.72 0.15 295);
--font-thv24-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-24 {
width: 100%;
min-height: 100svh;
}
.thv-24 ::selection {
background: var(--color-thv24-acc);
color: #000;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-thv24-bg: #0e0e12;
--color-thv24-bg: oklch(0.15 0.01 285);
--color-thv24-dim: #94949e;
--color-thv24-dim: oklch(0.67 0.01 285);
--color-thv24-acc: #a78bfa;
--color-thv24-acc: oklch(0.72 0.15 295);
--font-thv24-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-24 {
width: 100%;
min-height: 100svh;
}
.thv-24 ::selection {
background: var(--color-thv24-acc);
color: #000;
}@import "tailwindcss";
@theme {
--color-thv24-bg: #0e0e12;
--color-thv24-bg: oklch(0.15 0.01 285);
--color-thv24-dim: #94949e;
--color-thv24-dim: oklch(0.67 0.01 285);
--color-thv24-acc: #a78bfa;
--color-thv24-acc: oklch(0.72 0.15 295);
--font-thv24-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-24 {
width: 100%;
min-height: 100svh;
}
.thv-24 ::selection {
background: var(--color-thv24-acc);
color: #000;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;800&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Each card's lean and its shadow offset are neighbours in the class list, which makes the sign error that flattens the illusion impossible to miss.
- UI change from the CSS original: the cards are anchors with focus rings and
group-focus-visible:twins, the images have realalttext, and the captions — previously hover-only decoration — now appear for keyboard users too. motion-reduce:cancels the lean but keeps the sheen and caption, so no information is hidden behind motion.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Image Tilt Depth Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-image-tilt-depth-hover-effect/
Four photo cards that lean in 3D, each with a conic specular sheen and a caption that rises on hover. The shadow direction is matched to the lean on every variant, which is what sells the depth.
## HTML
```html
<section class="thv-24 w-full min-h-svh bg-thv24-bg font-thv24-sans px-8 py-12">
<p class="text-center text-[0.75rem] tracking-[0.14em] uppercase text-thv24-dim mb-10">Image Tilt Depth — 4 Variants</p>
<div class="flex flex-wrap justify-center items-start gap-10">
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[220px] aspect-[3/4] overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-y-[12deg] group-hover:rotate-x-[-6deg] group-hover:shadow-[-14px_18px_50px_rgba(0,0,0,.7)] group-focus-visible:rotate-y-[12deg] group-focus-visible:rotate-x-[-6deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:group-hover:rotate-x-0">
<img src="https://picsum.photos/seed/tilt1/300/400" alt="Portrait study in warm light" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Portrait Tilt</span>
</span>
</a>
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[320px] max-w-full aspect-video overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-x-[10deg] group-hover:rotate-y-[-5deg] group-hover:shadow-[0_-14px_40px_rgba(0,0,0,.6)] group-focus-visible:rotate-x-[10deg] group-focus-visible:rotate-y-[-5deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:rotate-y-0">
<img src="https://picsum.photos/seed/tilt2/400/260" alt="Wide landscape at golden hour" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Landscape Tilt</span>
</span>
</a>
<a href="#" class="group perspective-[500px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[220px] aspect-[3/4] overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-y-[-16deg] group-hover:rotate-x-[8deg] group-hover:shadow-[20px_14px_60px_rgba(0,0,0,.8)] group-focus-visible:rotate-y-[-16deg] group-focus-visible:rotate-x-[8deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:group-hover:rotate-x-0">
<img src="https://picsum.photos/seed/tilt3/300/400" alt="Architectural detail in shadow" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Deep Perspective</span>
</span>
</a>
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[320px] max-w-full aspect-video overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-x-[5deg] group-hover:rotate-y-[5deg] group-hover:translate-z-[12px] group-hover:shadow-[-8px_20px_50px_rgba(0,0,0,.65)] group-focus-visible:rotate-x-[5deg] group-focus-visible:rotate-y-[5deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:rotate-y-0">
<img src="https://picsum.photos/seed/tilt4/400/260" alt="Still life on a flat surface" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Flat Hover Lift</span>
</span>
</a>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv24-bg: #0e0e12;
--color-thv24-bg: oklch(0.15 0.01 285);
--color-thv24-dim: #94949e;
--color-thv24-dim: oklch(0.67 0.01 285);
--color-thv24-acc: #a78bfa;
--color-thv24-acc: oklch(0.72 0.15 295);
--font-thv24-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-24 {
width: 100%;
min-height: 100svh;
}
.thv-24 ::selection {
background: var(--color-thv24-acc);
color: #000;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Image Tilt Depth Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-image-tilt-depth-hover-effect/
Four photo cards that lean in 3D, each with a conic specular sheen and a caption that rises on hover. The shadow direction is matched to the lean on every variant, which is what sells the depth.
## HTML
```html
<section class="thv-24 w-full min-h-svh bg-thv24-bg font-thv24-sans px-8 py-12">
<p class="text-center text-[0.75rem] tracking-[0.14em] uppercase text-thv24-dim mb-10">Image Tilt Depth — 4 Variants</p>
<div class="flex flex-wrap justify-center items-start gap-10">
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[220px] aspect-[3/4] overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-y-[12deg] group-hover:rotate-x-[-6deg] group-hover:shadow-[-14px_18px_50px_rgba(0,0,0,.7)] group-focus-visible:rotate-y-[12deg] group-focus-visible:rotate-x-[-6deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:group-hover:rotate-x-0">
<img src="https://picsum.photos/seed/tilt1/300/400" alt="Portrait study in warm light" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Portrait Tilt</span>
</span>
</a>
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[320px] max-w-full aspect-video overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-x-[10deg] group-hover:rotate-y-[-5deg] group-hover:shadow-[0_-14px_40px_rgba(0,0,0,.6)] group-focus-visible:rotate-x-[10deg] group-focus-visible:rotate-y-[-5deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:rotate-y-0">
<img src="https://picsum.photos/seed/tilt2/400/260" alt="Wide landscape at golden hour" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Landscape Tilt</span>
</span>
</a>
<a href="#" class="group perspective-[500px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[220px] aspect-[3/4] overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-y-[-16deg] group-hover:rotate-x-[8deg] group-hover:shadow-[20px_14px_60px_rgba(0,0,0,.8)] group-focus-visible:rotate-y-[-16deg] group-focus-visible:rotate-x-[8deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:group-hover:rotate-x-0">
<img src="https://picsum.photos/seed/tilt3/300/400" alt="Architectural detail in shadow" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Deep Perspective</span>
</span>
</a>
<a href="#" class="group perspective-[700px] block rounded-xl no-underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv24-acc">
<span class="relative block w-[320px] max-w-full aspect-video overflow-hidden rounded-xl transform-3d shadow-[0_8px_30px_rgba(0,0,0,.55)] transition-[transform,box-shadow] duration-450 ease-[cubic-bezier(.23,1,.32,1)] group-hover:rotate-x-[5deg] group-hover:rotate-y-[5deg] group-hover:translate-z-[12px] group-hover:shadow-[-8px_20px_50px_rgba(0,0,0,.65)] group-focus-visible:rotate-x-[5deg] group-focus-visible:rotate-y-[5deg] motion-reduce:transition-none motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:rotate-y-0">
<img src="https://picsum.photos/seed/tilt4/400/260" alt="Still life on a flat surface" class="block w-full h-full object-cover">
<span aria-hidden="true" class="absolute inset-0 rounded-[inherit] opacity-0 pointer-events-none transition-opacity duration-400 bg-[conic-gradient(from_135deg_at_50%_0%,rgba(255,255,255,.18)_0deg,transparent_80deg)] group-hover:opacity-100 group-focus-visible:opacity-100"></span>
<span class="absolute inset-x-0 bottom-0 px-3.5 py-2.5 text-[0.78rem] tracking-[0.06em] text-white opacity-0 translate-y-1 transition-[opacity,transform] duration-350 bg-[linear-gradient(transparent,rgba(0,0,0,.75))] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0">Flat Hover Lift</span>
</span>
</a>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv24-bg: #0e0e12;
--color-thv24-bg: oklch(0.15 0.01 285);
--color-thv24-dim: #94949e;
--color-thv24-dim: oklch(0.67 0.01 285);
--color-thv24-acc: #a78bfa;
--color-thv24-acc: oklch(0.72 0.15 295);
--font-thv24-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-24 {
width: 100%;
min-height: 100svh;
}
.thv-24 ::selection {
background: var(--color-thv24-acc);
color: #000;
}
```How this works
Shell, frame, layers. The shell holds perspective; the frame holds transform-3d, the radius, the clipping and the shadow; the sheen and caption are absolutely positioned inside.
The shadow does the heavy lifting. Leaning right means the shadow moves left and grows — hover:shadow-[-14px_18px_50px_rgba(0,0,0,.7)]. Get that sign wrong and the card looks pasted on.
The caption is a second hover. opacity-0 translate-y-1 group-hover:opacity-100 group-hover:translate-y-0 over a bottom scrim, so the label arrives after the lean starts.
Make it yours
- Lean harder:
rotate-y-[18deg]with a proportionally longer shadow. - Sharper perspective:
perspective-[500px]. - Add a third depth layer with
group-hover:translate-z-[30px]on the caption.
Gotchas — read before shipping
overflow-hiddenon atransform-3delement flattens nested 3D in Safari — these cards keep the clip and put no 3D children inside it.- The sheen must be
pointer-events-noneor it swallows hover on the caption. transform-3dis needed on every intermediate container, not just the outermost.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
3D transforms and conic gradients are Baseline; the floor is Tailwind v4's generated sheet.