02 / 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 Hover Reveal Text Over Image
The portfolio-grid reveal: a gradient overlay fades in and its three text lines slide up in sequence. The CSS version staggers with duration multipliers; the port staggers with the per-item index pattern — each line carries style="--i:1" and one shared utility reads it, so the cascade tempo is a single number.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tih-02 w-full min-h-svh grid place-items-center bg-tih02-bg font-tih02-sans px-6 py-10" aria-label="Hover reveal text over image demo">
<div class="grid w-full max-w-195 gap-4 grid-cols-1 sm:grid-cols-3">
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-nebula/600/800'),linear-gradient(160deg,oklch(0.17_0.07_285),oklch(0.34_0.12_285),oklch(0.28_0.06_290))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Portfolio</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Astrophotography</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#nebula" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Nebula Series Vol. 3</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Shot over 14 nights in the Chilean Atacama desert</p>
</div>
</article>
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-city/600/800'),linear-gradient(160deg,oklch(0.2_0.03_220),oklch(0.32_0.04_215),oklch(0.42_0.05_235))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Architecture</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Urban Design</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#cityscapes" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Midnight Cityscapes</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Long exposure study of downtown light trails</p>
</div>
</article>
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-prism/600/800'),linear-gradient(160deg,oklch(0.17_0.09_320),oklch(0.29_0.15_325),oklch(0.32_0.12_290))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Abstract</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Digital Art</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#prism" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Prism Light Study</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Generative colour diffraction experiments</p>
</div>
</article>
</div>
</section><section class="tih-02 w-full min-h-svh grid place-items-center bg-tih02-bg font-tih02-sans px-6 py-10" aria-label="Hover reveal text over image demo">
<div class="grid w-full max-w-195 gap-4 grid-cols-1 sm:grid-cols-3">
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-nebula/600/800'),linear-gradient(160deg,oklch(0.17_0.07_285),oklch(0.34_0.12_285),oklch(0.28_0.06_290))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Portfolio</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Astrophotography</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#nebula" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Nebula Series Vol. 3</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Shot over 14 nights in the Chilean Atacama desert</p>
</div>
</article>
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-city/600/800'),linear-gradient(160deg,oklch(0.2_0.03_220),oklch(0.32_0.04_215),oklch(0.42_0.05_235))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Architecture</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Urban Design</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#cityscapes" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Midnight Cityscapes</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Long exposure study of downtown light trails</p>
</div>
</article>
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-prism/600/800'),linear-gradient(160deg,oklch(0.17_0.09_320),oklch(0.29_0.15_325),oklch(0.32_0.12_290))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Abstract</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Digital Art</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#prism" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Prism Light Study</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Generative colour diffraction experiments</p>
</div>
</article>
</div>
</section>@import "tailwindcss";
@theme {
--color-tih02-bg: #09090f;
--color-tih02-bg: oklch(0.13 0.008 285);
--color-tih02-text: #f1f5f9;
--color-tih02-text: oklch(0.96 0.005 250);
--color-tih02-muted: #94a3b8;
--color-tih02-muted: oklch(0.7 0.03 250);
--color-tih02-acc: #06b6d4;
--color-tih02-acc: oklch(0.71 0.14 205);
--font-tih02-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih02: cubic-bezier(0.16, 1, 0.3, 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-02 {
width: 100%;
min-height: 100svh;
}
.tih-02 ::selection {
background: oklch(0.71 0.14 205);
color: #000;
}@import "tailwindcss";
@theme {
--color-tih02-bg: #09090f;
--color-tih02-bg: oklch(0.13 0.008 285);
--color-tih02-text: #f1f5f9;
--color-tih02-text: oklch(0.96 0.005 250);
--color-tih02-muted: #94a3b8;
--color-tih02-muted: oklch(0.7 0.03 250);
--color-tih02-acc: #06b6d4;
--color-tih02-acc: oklch(0.71 0.14 205);
--font-tih02-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih02: cubic-bezier(0.16, 1, 0.3, 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-02 {
width: 100%;
min-height: 100svh;
}
.tih-02 ::selection {
background: oklch(0.71 0.14 205);
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-tih02-bg: #09090f;
--color-tih02-bg: oklch(0.13 0.008 285);
--color-tih02-text: #f1f5f9;
--color-tih02-text: oklch(0.96 0.005 250);
--color-tih02-muted: #94a3b8;
--color-tih02-muted: oklch(0.7 0.03 250);
--color-tih02-acc: #06b6d4;
--color-tih02-acc: oklch(0.71 0.14 205);
--font-tih02-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih02: cubic-bezier(0.16, 1, 0.3, 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-02 {
width: 100%;
min-height: 100svh;
}
.tih-02 ::selection {
background: oklch(0.71 0.14 205);
color: #000;
}@import "tailwindcss";
@theme {
--color-tih02-bg: #09090f;
--color-tih02-bg: oklch(0.13 0.008 285);
--color-tih02-text: #f1f5f9;
--color-tih02-text: oklch(0.96 0.005 250);
--color-tih02-muted: #94a3b8;
--color-tih02-muted: oklch(0.7 0.03 250);
--color-tih02-acc: #06b6d4;
--color-tih02-acc: oklch(0.71 0.14 205);
--font-tih02-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih02: cubic-bezier(0.16, 1, 0.3, 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-02 {
width: 100%;
min-height: 100svh;
}
.tih-02 ::selection {
background: oklch(0.71 0.14 205);
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&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.
- Six descendant hover rules become
group-hover:utilities on the six elements that respond — the overlay, the artwork, the glyph and the three lines. - The duration-multiplier fake stagger (
calc(var(--duration)*1.1)) is replaced by realtransition-delaydriven by--i. Same effect, honest mechanism, and every line now shares one duration. - The delay utility sits inside
group-hover:only, so the exit is simultaneous. The CSS version's multiplier applies in both directions, which is why its mouse-out feels sticky. - The three-stop scrim stays a single arbitrary
bg-linear-[…]utility: a tuned gradient is a one-off value, not a token. motion-reduce:turns the whole interaction into a permanently visible caption — two variants per line instead of a media-query block that has to restate every selector.pointer-events-noneon the scrim withpointer-events-autoon the link is the utility pair that keeps a decorative overlay from eating the click.
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 Hover Reveal Text Over Image
Source: https://codefronts.com/motion/tailwind-css-image-hover-effects/tailwind-hover-reveal-text-over-image/
The portfolio-grid reveal: a gradient overlay fades in and its three text lines slide up in sequence. The CSS version staggers with duration multipliers; the port staggers with the per-item index pattern — each line carries style="--i:1" and one shared utility reads it, so the cascade tempo is a single number.
## HTML
```html
<section class="tih-02 w-full min-h-svh grid place-items-center bg-tih02-bg font-tih02-sans px-6 py-10" aria-label="Hover reveal text over image demo">
<div class="grid w-full max-w-195 gap-4 grid-cols-1 sm:grid-cols-3">
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-nebula/600/800'),linear-gradient(160deg,oklch(0.17_0.07_285),oklch(0.34_0.12_285),oklch(0.28_0.06_290))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Portfolio</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Astrophotography</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#nebula" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Nebula Series Vol. 3</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Shot over 14 nights in the Chilean Atacama desert</p>
</div>
</article>
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-city/600/800'),linear-gradient(160deg,oklch(0.2_0.03_220),oklch(0.32_0.04_215),oklch(0.42_0.05_235))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Architecture</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Urban Design</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#cityscapes" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Midnight Cityscapes</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Long exposure study of downtown light trails</p>
</div>
</article>
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-prism/600/800'),linear-gradient(160deg,oklch(0.17_0.09_320),oklch(0.29_0.15_325),oklch(0.32_0.12_290))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Abstract</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Digital Art</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#prism" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Prism Light Study</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Generative colour diffraction experiments</p>
</div>
</article>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tih02-bg: #09090f;
--color-tih02-bg: oklch(0.13 0.008 285);
--color-tih02-text: #f1f5f9;
--color-tih02-text: oklch(0.96 0.005 250);
--color-tih02-muted: #94a3b8;
--color-tih02-muted: oklch(0.7 0.03 250);
--color-tih02-acc: #06b6d4;
--color-tih02-acc: oklch(0.71 0.14 205);
--font-tih02-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih02: cubic-bezier(0.16, 1, 0.3, 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-02 {
width: 100%;
min-height: 100svh;
}
.tih-02 ::selection {
background: oklch(0.71 0.14 205);
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 Hover Reveal Text Over Image
Source: https://codefronts.com/motion/tailwind-css-image-hover-effects/tailwind-hover-reveal-text-over-image/
The portfolio-grid reveal: a gradient overlay fades in and its three text lines slide up in sequence. The CSS version staggers with duration multipliers; the port staggers with the per-item index pattern — each line carries style="--i:1" and one shared utility reads it, so the cascade tempo is a single number.
## HTML
```html
<section class="tih-02 w-full min-h-svh grid place-items-center bg-tih02-bg font-tih02-sans px-6 py-10" aria-label="Hover reveal text over image demo">
<div class="grid w-full max-w-195 gap-4 grid-cols-1 sm:grid-cols-3">
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-nebula/600/800'),linear-gradient(160deg,oklch(0.17_0.07_285),oklch(0.34_0.12_285),oklch(0.28_0.06_290))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Portfolio</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Astrophotography</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#nebula" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Nebula Series Vol. 3</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Shot over 14 nights in the Chilean Atacama desert</p>
</div>
</article>
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-city/600/800'),linear-gradient(160deg,oklch(0.2_0.03_220),oklch(0.32_0.04_215),oklch(0.42_0.05_235))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Architecture</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Urban Design</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#cityscapes" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Midnight Cityscapes</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Long exposure study of downtown light trails</p>
</div>
</article>
<article class="group relative overflow-hidden rounded-xl aspect-[3/4]">
<div class="grid place-items-center w-full h-full bg-[image:url('https://picsum.photos/seed/tih02-prism/600/800'),linear-gradient(160deg,oklch(0.17_0.09_320),oklch(0.29_0.15_325),oklch(0.32_0.12_290))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih02 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
<span class="absolute top-3 left-3 z-2 px-2 py-1 rounded-md text-[10px] font-semibold tracking-[0.05em] text-tih02-muted bg-[oklch(0_0_0/0.5)] backdrop-blur-md border border-[oklch(1_0_0/0.1)]">Abstract</span>
<div class="absolute inset-0 z-1 flex flex-col justify-end p-4 pointer-events-none bg-linear-[to_top,oklch(0_0_0/0.85),oklch(0_0_0/0.3)_50%,transparent] opacity-0 transition-opacity duration-400 ease-tih02 group-hover:opacity-100 motion-reduce:transition-none motion-reduce:opacity-100">
<p style="--i:0" class="mb-1.5 text-[10px] font-bold tracking-[0.1em] uppercase text-tih02-acc opacity-0 translate-y-3 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Digital Art</p>
<h3 style="--i:1" class="text-[15px] font-bold leading-[1.3] text-tih02-text opacity-0 translate-y-4 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0"><a href="#prism" class="pointer-events-auto no-underline text-inherit rounded focus-visible:outline-2 focus-visible:outline-tih02-acc focus-visible:outline-offset-3">Prism Light Study</a></h3>
<p style="--i:2" class="mt-1 text-xs text-tih02-muted opacity-0 translate-y-5 transition-[opacity,translate] duration-400 ease-tih02 group-hover:opacity-100 group-hover:translate-y-0 group-hover:[transition-delay:calc(var(--i)*70ms)] motion-reduce:transition-none motion-reduce:opacity-100 motion-reduce:translate-y-0">Generative colour diffraction experiments</p>
</div>
</article>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tih02-bg: #09090f;
--color-tih02-bg: oklch(0.13 0.008 285);
--color-tih02-text: #f1f5f9;
--color-tih02-text: oklch(0.96 0.005 250);
--color-tih02-muted: #94a3b8;
--color-tih02-muted: oklch(0.7 0.03 250);
--color-tih02-acc: #06b6d4;
--color-tih02-acc: oklch(0.71 0.14 205);
--font-tih02-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih02: cubic-bezier(0.16, 1, 0.3, 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-02 {
width: 100%;
min-height: 100svh;
}
.tih-02 ::selection {
background: oklch(0.71 0.14 205);
color: #000;
}
```How this works
One overlay, one variant. The scrim is an absolutely positioned sibling at opacity-0 that becomes group-hover:opacity-100. Nothing else about it changes, so it can be a static gradient utility.
The stagger is data, not rules. The CSS collection multiplies durations (×1.1, ×1.2) to fake a cascade. The port uses real delays driven by an index:
<p style="--i:1" class="opacity-0 translate-y-4
transition-[opacity,translate] duration-400
group-hover:opacity-100 group-hover:translate-y-0
group-hover:[transition-delay:calc(var(--i)*70ms)]">Every line shares one class list and differs by one number. Adding a fourth line is a copy and an increment, and the tempo is the 70ms — changed once, felt everywhere.
Delays belong to the open half only. The delay utility is inside group-hover:, so the lines leave together on mouse-out instead of unwinding in slow sequence — which is what a staggered exit feels like, and it always feels wrong.
Make it yours
- Cascade tempo: the
70msmultiplier. Zero makes the lines arrive with the scrim;120msmakes it theatrical. - Direction: swap
translate-y-4for-translate-x-4on the lines and the caption wipes in from the left. - Scrim character: replace the gradient utility with
bg-[oklch(0_0_0/0.6)]for a flat high-contrast editorial wash. - Add
group-hover:scale-108to the artwork layer for depth — it is already inside theoverflow-hiddenclip. - Retheme through
--color-tih02-acc; the eyebrow, the badge border and every focus ring read it.
Gotchas — read before shipping
- The overlay must be
pointer-events-noneor it swallows clicks on the link underneath — a hover reveal that cannot be clicked is the most common version of this bug. [transition-delay:calc(var(--i)*70ms)]must be typed without spaces; the underscore escape carries any multi-token value.- Keep the always-visible badge OUTSIDE the overlay. Inside, the resting card has no label at all — and neither does a touch device, which has no hover.
- Never animate
hiddenorinvisiblehere: they do not interpolate. Opacity pluspointer-events-noneis the pair that works. - The class strings must be statically visible to the compiler. A delay assembled from a template variable produces no CSS — keep the varying part in
--i. - 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+ |
Opacity and transform transitions are universally supported; backdrop-blur on the badge needs Firefox 103+. The floor quoted is Tailwind v4's own generated sheet.