20 / 20
All 20 in 20 Tailwind CSS Image Hover Effects
- 01Tailwind Image Hover Zoom In Card
- 02Tailwind Hover Reveal Text Over Image
- 03Tailwind E-Commerce Product Image Swap on Hover
- 04Tailwind Grid Image Blur Overlay Text Hover
- 05Tailwind Card Slide Up Caption on Hover
- 06Tailwind Grayscale to Color Image Hover
- 07Tailwind Image Color Overlay Tint on Hover
- 08Tailwind Neumorphic Image Card Hover Effect
- 09Tailwind Glassmorphism Overlay on Image Hover
- 10Tailwind Glowing Neon Border Image Hover
- 11Tailwind Image Clip-Path Transition Hover
- 12Tailwind Image Tilt 3D Perspective Hover
- 13Tailwind Shining Light Glare Image Hover
- 14Tailwind Image Split Transition Hover
- 15Tailwind Image Ripple Animation Hover
- 16Tailwind Circular Team Profile Avatar Hover
- 17Tailwind Fullscreen Background Image Hover
- 18Tailwind Masonry Gallery Zoom Hover
- 19Tailwind Image Icon Reveal Center Hover
- 20Tailwind Image Card Flip 3D Animation Hover
Tailwind Image Card Flip 3D Animation Hover
The three-layer flip — scene, flipper, two faces — with every one of its four critical properties now a named utility: [perspective:800px], transform-3d, backface-hidden and group-hover:rotate-y-180. The pattern's failure modes are all “you forgot one of these”, and a class list makes a missing one visible.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tih-20 w-full min-h-svh grid place-items-center bg-tih20-bg font-tih20-sans px-6 py-10" aria-label="3D card flip hover demo">
<div class="grid w-full max-w-195 gap-5 grid-cols-1 sm:grid-cols-3">
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-cosmos/600/800'),linear-gradient(145deg,oklch(0.25_0.1_285),oklch(0.35_0.15_280),oklch(0.5_0.2_275),oklch(0.72_0.14_275))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Cosmos Explorer</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Astrophotography</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.18_0.07_285),oklch(0.25_0.1_285)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🌌</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">20-Week Course</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">Master astrophotography from light-pollution basics to deep-sky stacking.</p>
<a href="#cosmos-enroll" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.8_0.14_163/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Enroll Now</a>
</div>
</div>
</div>
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-bio/600/800'),linear-gradient(145deg,oklch(0.22_0.06_150),oklch(0.35_0.09_150),oklch(0.55_0.13_155),oklch(0.8_0.14_163))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Bio Systems</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Botany Research</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.15_0.05_150),oklch(0.22_0.06_150)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🧬</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">Lab Access</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">12 months of virtual lab sessions with live microscopy and specimen archives.</p>
<a href="#bio-join" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.8_0.14_163/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Join Lab</a>
</div>
</div>
</div>
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-arts/600/800'),linear-gradient(145deg,oklch(0.25_0.13_305),oklch(0.4_0.19_302),oklch(0.55_0.22_300),oklch(0.78_0.19_320))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Digital Arts</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Creative Studio</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.17_0.09_310),oklch(0.25_0.13_305)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🎨</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">Creator Pack</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">Unlimited generative art tools, 500+ premium assets and weekly critique sessions.</p>
<a href="#arts-access" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc2 transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.78_0.19_320/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Get Access</a>
</div>
</div>
</div>
</div>
</section><section class="tih-20 w-full min-h-svh grid place-items-center bg-tih20-bg font-tih20-sans px-6 py-10" aria-label="3D card flip hover demo">
<div class="grid w-full max-w-195 gap-5 grid-cols-1 sm:grid-cols-3">
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-cosmos/600/800'),linear-gradient(145deg,oklch(0.25_0.1_285),oklch(0.35_0.15_280),oklch(0.5_0.2_275),oklch(0.72_0.14_275))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Cosmos Explorer</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Astrophotography</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.18_0.07_285),oklch(0.25_0.1_285)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🌌</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">20-Week Course</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">Master astrophotography from light-pollution basics to deep-sky stacking.</p>
<a href="#cosmos-enroll" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.8_0.14_163/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Enroll Now</a>
</div>
</div>
</div>
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-bio/600/800'),linear-gradient(145deg,oklch(0.22_0.06_150),oklch(0.35_0.09_150),oklch(0.55_0.13_155),oklch(0.8_0.14_163))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Bio Systems</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Botany Research</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.15_0.05_150),oklch(0.22_0.06_150)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🧬</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">Lab Access</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">12 months of virtual lab sessions with live microscopy and specimen archives.</p>
<a href="#bio-join" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.8_0.14_163/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Join Lab</a>
</div>
</div>
</div>
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-arts/600/800'),linear-gradient(145deg,oklch(0.25_0.13_305),oklch(0.4_0.19_302),oklch(0.55_0.22_300),oklch(0.78_0.19_320))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Digital Arts</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Creative Studio</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.17_0.09_310),oklch(0.25_0.13_305)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🎨</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">Creator Pack</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">Unlimited generative art tools, 500+ premium assets and weekly critique sessions.</p>
<a href="#arts-access" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc2 transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.78_0.19_320/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Get Access</a>
</div>
</div>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-tih20-bg: #07070f;
--color-tih20-bg: oklch(0.11 0.012 285);
--color-tih20-text: #f1f5f9;
--color-tih20-text: oklch(0.96 0.005 250);
--color-tih20-muted: #64748b;
--color-tih20-muted: oklch(0.68 0.03 255);
--color-tih20-acc: #34d399;
--color-tih20-acc: oklch(0.8 0.14 163);
--color-tih20-acc2: #e879f9;
--color-tih20-acc2: oklch(0.78 0.19 320);
--font-tih20-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih20: cubic-bezier(0.45, 0, 0.55, 1);
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is correctly sized before the browser build compiles. */
.tih-20 {
width: 100%;
min-height: 100svh;
}
.tih-20 ::selection {
background: oklch(0.8 0.14 163);
color: #000;
}
/* Firefox subpixel artefacts on face edges inside a 3D context. A bug workaround,
which is exactly the category that should stay out of the markup. */
.tih-20 .backface-hidden {
border: 1px solid transparent;
}@import "tailwindcss";
@theme {
--color-tih20-bg: #07070f;
--color-tih20-bg: oklch(0.11 0.012 285);
--color-tih20-text: #f1f5f9;
--color-tih20-text: oklch(0.96 0.005 250);
--color-tih20-muted: #64748b;
--color-tih20-muted: oklch(0.68 0.03 255);
--color-tih20-acc: #34d399;
--color-tih20-acc: oklch(0.8 0.14 163);
--color-tih20-acc2: #e879f9;
--color-tih20-acc2: oklch(0.78 0.19 320);
--font-tih20-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih20: cubic-bezier(0.45, 0, 0.55, 1);
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is correctly sized before the browser build compiles. */
.tih-20 {
width: 100%;
min-height: 100svh;
}
.tih-20 ::selection {
background: oklch(0.8 0.14 163);
color: #000;
}
/* Firefox subpixel artefacts on face edges inside a 3D context. A bug workaround,
which is exactly the category that should stay out of the markup. */
.tih-20 .backface-hidden {
border: 1px solid transparent;
}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-tih20-bg: #07070f;
--color-tih20-bg: oklch(0.11 0.012 285);
--color-tih20-text: #f1f5f9;
--color-tih20-text: oklch(0.96 0.005 250);
--color-tih20-muted: #64748b;
--color-tih20-muted: oklch(0.68 0.03 255);
--color-tih20-acc: #34d399;
--color-tih20-acc: oklch(0.8 0.14 163);
--color-tih20-acc2: #e879f9;
--color-tih20-acc2: oklch(0.78 0.19 320);
--font-tih20-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih20: cubic-bezier(0.45, 0, 0.55, 1);
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is correctly sized before the browser build compiles. */
.tih-20 {
width: 100%;
min-height: 100svh;
}
.tih-20 ::selection {
background: oklch(0.8 0.14 163);
color: #000;
}
/* Firefox subpixel artefacts on face edges inside a 3D context. A bug workaround,
which is exactly the category that should stay out of the markup. */
.tih-20 .backface-hidden {
border: 1px solid transparent;
}@import "tailwindcss";
@theme {
--color-tih20-bg: #07070f;
--color-tih20-bg: oklch(0.11 0.012 285);
--color-tih20-text: #f1f5f9;
--color-tih20-text: oklch(0.96 0.005 250);
--color-tih20-muted: #64748b;
--color-tih20-muted: oklch(0.68 0.03 255);
--color-tih20-acc: #34d399;
--color-tih20-acc: oklch(0.8 0.14 163);
--color-tih20-acc2: #e879f9;
--color-tih20-acc2: oklch(0.78 0.19 320);
--font-tih20-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih20: cubic-bezier(0.45, 0, 0.55, 1);
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is correctly sized before the browser build compiles. */
.tih-20 {
width: 100%;
min-height: 100svh;
}
.tih-20 ::selection {
background: oklch(0.8 0.14 163);
color: #000;
}
/* Firefox subpixel artefacts on face edges inside a 3D context. A bug workaround,
which is exactly the category that should stay out of the markup. */
.tih-20 .backface-hidden {
border: 1px solid transparent;
}<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&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&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- All four of the pattern's load-bearing properties become utilities on the three elements that need them, so a missing one is visible in the markup rather than diagnosed from a broken flip.
backface-hiddenemits the-webkit-prefix; the CSS version has to write both by hand on both faces.rotate-y-180appears twice with different meanings — statically on the back face, undergroup-hover:on the flipper — and reading them together is what makes the mechanism obvious.focus-within:rotate-y-180is added by the port. The back face holds the CTA, and in the CSS original that CTA is focusable while invisible.motion-reduce:converts the flip into a cross-fade rather than merely disabling it, so the back content is still reachable without a 180° rotation.- The clip stays on the faces and never on the flipper — the one rule that makes 3D flips work, and the split is enforced by which element carries
overflow-hidden.
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 Card Flip 3D Animation Hover
Source: https://codefronts.com/motion/tailwind-css-image-hover-effects/tailwind-image-card-flip-3d-animation-hover/
The three-layer flip — scene, flipper, two faces — with every one of its four critical properties now a named utility: [perspective:800px], transform-3d, backface-hidden and group-hover:rotate-y-180. The pattern's failure modes are all “you forgot one of these”, and a class list makes a missing one visible.
## HTML
```html
<section class="tih-20 w-full min-h-svh grid place-items-center bg-tih20-bg font-tih20-sans px-6 py-10" aria-label="3D card flip hover demo">
<div class="grid w-full max-w-195 gap-5 grid-cols-1 sm:grid-cols-3">
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-cosmos/600/800'),linear-gradient(145deg,oklch(0.25_0.1_285),oklch(0.35_0.15_280),oklch(0.5_0.2_275),oklch(0.72_0.14_275))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Cosmos Explorer</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Astrophotography</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.18_0.07_285),oklch(0.25_0.1_285)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🌌</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">20-Week Course</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">Master astrophotography from light-pollution basics to deep-sky stacking.</p>
<a href="#cosmos-enroll" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.8_0.14_163/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Enroll Now</a>
</div>
</div>
</div>
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-bio/600/800'),linear-gradient(145deg,oklch(0.22_0.06_150),oklch(0.35_0.09_150),oklch(0.55_0.13_155),oklch(0.8_0.14_163))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Bio Systems</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Botany Research</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.15_0.05_150),oklch(0.22_0.06_150)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🧬</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">Lab Access</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">12 months of virtual lab sessions with live microscopy and specimen archives.</p>
<a href="#bio-join" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.8_0.14_163/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Join Lab</a>
</div>
</div>
</div>
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-arts/600/800'),linear-gradient(145deg,oklch(0.25_0.13_305),oklch(0.4_0.19_302),oklch(0.55_0.22_300),oklch(0.78_0.19_320))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Digital Arts</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Creative Studio</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.17_0.09_310),oklch(0.25_0.13_305)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🎨</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">Creator Pack</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">Unlimited generative art tools, 500+ premium assets and weekly critique sessions.</p>
<a href="#arts-access" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc2 transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.78_0.19_320/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Get Access</a>
</div>
</div>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tih20-bg: #07070f;
--color-tih20-bg: oklch(0.11 0.012 285);
--color-tih20-text: #f1f5f9;
--color-tih20-text: oklch(0.96 0.005 250);
--color-tih20-muted: #64748b;
--color-tih20-muted: oklch(0.68 0.03 255);
--color-tih20-acc: #34d399;
--color-tih20-acc: oklch(0.8 0.14 163);
--color-tih20-acc2: #e879f9;
--color-tih20-acc2: oklch(0.78 0.19 320);
--font-tih20-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih20: cubic-bezier(0.45, 0, 0.55, 1);
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is correctly sized before the browser build compiles. */
.tih-20 {
width: 100%;
min-height: 100svh;
}
.tih-20 ::selection {
background: oklch(0.8 0.14 163);
color: #000;
}
/* Firefox subpixel artefacts on face edges inside a 3D context. A bug workaround,
which is exactly the category that should stay out of the markup. */
.tih-20 .backface-hidden {
border: 1px solid transparent;
}
```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 Card Flip 3D Animation Hover
Source: https://codefronts.com/motion/tailwind-css-image-hover-effects/tailwind-image-card-flip-3d-animation-hover/
The three-layer flip — scene, flipper, two faces — with every one of its four critical properties now a named utility: [perspective:800px], transform-3d, backface-hidden and group-hover:rotate-y-180. The pattern's failure modes are all “you forgot one of these”, and a class list makes a missing one visible.
## HTML
```html
<section class="tih-20 w-full min-h-svh grid place-items-center bg-tih20-bg font-tih20-sans px-6 py-10" aria-label="3D card flip hover demo">
<div class="grid w-full max-w-195 gap-5 grid-cols-1 sm:grid-cols-3">
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-cosmos/600/800'),linear-gradient(145deg,oklch(0.25_0.1_285),oklch(0.35_0.15_280),oklch(0.5_0.2_275),oklch(0.72_0.14_275))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Cosmos Explorer</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Astrophotography</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.18_0.07_285),oklch(0.25_0.1_285)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🌌</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">20-Week Course</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">Master astrophotography from light-pollution basics to deep-sky stacking.</p>
<a href="#cosmos-enroll" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.8_0.14_163/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Enroll Now</a>
</div>
</div>
</div>
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-bio/600/800'),linear-gradient(145deg,oklch(0.22_0.06_150),oklch(0.35_0.09_150),oklch(0.55_0.13_155),oklch(0.8_0.14_163))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Bio Systems</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Botany Research</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.15_0.05_150),oklch(0.22_0.06_150)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🧬</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">Lab Access</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">12 months of virtual lab sessions with live microscopy and specimen archives.</p>
<a href="#bio-join" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.8_0.14_163/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Join Lab</a>
</div>
</div>
</div>
<div class="group [perspective:800px] aspect-[3/4]">
<div class="relative w-full h-full transform-3d transition-transform duration-650 ease-tih20 group-hover:rotate-y-180 focus-within:rotate-y-180 motion-reduce:transition-none motion-reduce:group-hover:rotate-y-0 motion-reduce:focus-within:rotate-y-0">
<div class="absolute inset-0 flex flex-col justify-end overflow-hidden rounded-2xl backface-hidden bg-[image:url('https://picsum.photos/seed/tih20-arts/600/800'),linear-gradient(145deg,oklch(0.25_0.13_305),oklch(0.4_0.19_302),oklch(0.55_0.22_300),oklch(0.78_0.19_320))] bg-cover bg-center bg-no-repeat motion-reduce:opacity-100 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-0">
<div class="relative z-1 p-4 bg-linear-[to_top,oklch(0_0_0/0.8),transparent]">
<p class="text-sm font-bold text-tih20-text">Digital Arts</p>
<p class="mt-0.5 text-[10px] text-tih20-muted">Creative Studio</p>
</div>
<span class="absolute top-2.5 right-2.5 z-2 px-2 py-0.75 rounded-full text-[9px] font-bold text-tih20-muted bg-[oklch(1_0_0/0.07)] border border-[oklch(1_0_0/0.1)] transition-opacity duration-300 group-hover:opacity-0">Hover to flip</span>
</div>
<div class="absolute inset-0 flex flex-col items-center justify-center p-5 overflow-hidden rounded-2xl backface-hidden rotate-y-180 bg-linear-[135deg,oklch(0.17_0.09_310),oklch(0.25_0.13_305)] motion-reduce:opacity-0 motion-reduce:rotate-y-0 motion-reduce:transition-opacity motion-reduce:duration-300 motion-reduce:group-hover:opacity-100">
<span class="mb-3 text-4xl" aria-hidden="true">🎨</span>
<p class="mb-2 text-[15px] font-extrabold text-center text-tih20-text">Creator Pack</p>
<p class="mb-3.5 text-[11px] leading-[1.5] text-center text-tih20-muted">Unlimited generative art tools, 500+ premium assets and weekly critique sessions.</p>
<a href="#arts-access" class="px-4.5 py-2 rounded-full text-[11px] font-bold tracking-[0.05em] text-black no-underline bg-tih20-acc2 transition-[scale,box-shadow] duration-200 hover:scale-104 hover:shadow-[0_0_16px_oklch(0.78_0.19_320/0.4)] focus-visible:outline-2 focus-visible:outline-tih20-text focus-visible:outline-offset-2 motion-reduce:transition-none">Get Access</a>
</div>
</div>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tih20-bg: #07070f;
--color-tih20-bg: oklch(0.11 0.012 285);
--color-tih20-text: #f1f5f9;
--color-tih20-text: oklch(0.96 0.005 250);
--color-tih20-muted: #64748b;
--color-tih20-muted: oklch(0.68 0.03 255);
--color-tih20-acc: #34d399;
--color-tih20-acc: oklch(0.8 0.14 163);
--color-tih20-acc2: #e879f9;
--color-tih20-acc2: oklch(0.78 0.19 320);
--font-tih20-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih20: cubic-bezier(0.45, 0, 0.55, 1);
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is correctly sized before the browser build compiles. */
.tih-20 {
width: 100%;
min-height: 100svh;
}
.tih-20 ::selection {
background: oklch(0.8 0.14 163);
color: #000;
}
/* Firefox subpixel artefacts on face edges inside a 3D context. A bug workaround,
which is exactly the category that should stay out of the markup. */
.tih-20 .backface-hidden {
border: 1px solid transparent;
}
```How this works
Four properties, four utilities.
<div class="[perspective:800px] aspect-[3/4]"> <!-- scene -->
<div class="relative w-full h-full transform-3d
transition-transform duration-650
group-hover:rotate-y-180"> <!-- flipper -->
<div class="absolute inset-0 backface-hidden">…front
<div class="absolute inset-0 backface-hidden rotate-y-180">…backDrop transform-3d and the faces flatten into a scale-through. Drop backface-hidden and both faces show at once. Because all four live in class lists on the three elements, the structure is auditable at a glance — which is not true of four declarations spread over three rules.
Never clip the flipper. overflow-hidden on an element with transform-style: preserve-3d breaks the 3D context in every engine. The rounding and clipping go on the faces instead, and the utility split makes that easy to keep straight.
Reduced motion gets a cross-fade. A 180° rotation is exactly the kind of motion the media query exists for, so motion-reduce: cancels the rotation and swaps the faces by opacity instead.
Make it yours
- Axis:
rotate-x-180on both the back face and the hover state for a vertical flip. - Pace:
duration-650→duration-400for a snap,duration-900for a slow turn. - Depth: the
800pxin the scene's perspective — smaller is more dramatic. - Tap to flip: add a
data-flippedattribute and agroup-data-flipped:rotate-y-180variant alongside the hover one; four lines of JS for touch. - Retheme through
--color-tih20-acc; the CTA and focus rings read it.
Gotchas — read before shipping
overflow-hiddenandtransform-3dmust never share an element — the 3D context collapses. Put the clip on the faces.- Both faces need
backface-hidden, not just the back one. - The back face must be pre-rotated 180°, or it arrives mirrored.
- Hover-only flipping hides the back face's CTA from keyboard users;
focus-within:rotate-y-180is the two-word fix. - Firefox can show subpixel artefacts on face edges in a 3D context; the transparent hairline border stays in the stylesheet for that.
- The browser CDN build compiles in the page and is for prototyping only. Ship the CLI or a plugin build.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
3D transforms are broadly supported; backface-hidden emits the -webkit- prefix automatically, which hand-written CSS has to remember.