21 / 22
All 22 in 22 Tailwind CSS Image Gallery
- 01Tailwind Hexagon Honeycomb Image Gallery with clip-path
- 02Tailwind Justified Image Gallery with Aspect-Ratio Flex Rows
- 03Tailwind Expanding Panel Image Gallery with Flex-Grow Transitions
- 04Tailwind :has() Hover Spotlight Image Grid
- 05Tailwind Radial Orbit Image Gallery with Counter-Rotating Thumbnails
- 06Tailwind Interactive Pointer Trail Image Gallery
- 07Tailwind Masonry Image Gallery with CSS Columns (No JavaScript)
- 08Tailwind Metro Tile Grid Gallery with Dense Auto-Flow
- 09Tailwind Editorial Magazine Grid Gallery with Blend-Mode Headline
- 10Tailwind Pure CSS Lightbox Gallery with :target (No JavaScript)
- 11Tailwind Filmstrip Carousel Gallery with CSS Scroll-Snap
- 12Tailwind Accordion Image Gallery with Flex-Grow on Hover & Focus
- 13Tailwind Mosaic Grid Gallery with Contained Zoom on Hover
- 14Tailwind Glassmorphism Image Cards with backdrop-blur
- 15Tailwind Diagonal Slice Reveal Gallery with clip-path Halves
- 16Tailwind 3D Tilt Parallax Image Cards with Pointer-Driven Variables
- 17Tailwind 3D Cube Image Viewer with Radio-Driven Rotation
- 18Tailwind 3D Perspective Depth Stack Gallery That Fans on Focus
- 19Tailwind Infinite Scrolling Image Marquee with Seamless Loop
- 20Tailwind Ken Burns Slideshow Gallery with Staggered Cross-Fade
- 21Tailwind Polaroid Photo Stack Gallery with Rotate-on-Hover
- 22Tailwind Scattered Photo Collage with :target Spotlight
Tailwind Polaroid Photo Stack Gallery with Rotate-on-Hover
Photographs styled as vintage Polaroid prints — thick white frame, deep bottom border, handwritten caption — tossed at casual angles and straightening with a lift as you reach for one. Each print's resting angle is a utility on the print, not an nth-child rule.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tgl-21 w-full min-h-svh grid place-items-center bg-tgl21-bg font-tgl21-sans px-5 py-10 bg-[radial-gradient(rgba(120,100,80,0.14)_1px,transparent_1px)] [background-size:6px_6px]" aria-label="Polaroid stack gallery">
<div class="flex flex-wrap items-center justify-center gap-1.5 w-[min(820px,100%)]">
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-6deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?q=80&w=400&h=400&auto=format&fit=crop" alt="Friends on a summer trip" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Summer '24</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[4deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?q=80&w=400&h=400&auto=format&fit=crop" alt="Sunset on the beach" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Last light</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-3deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1499346030926-9a72daac6c63?q=80&w=400&h=400&auto=format&fit=crop" alt="Road trip stop at a filling station" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Route 1</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[5deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1620121692029-d088224ddc74?q=80&w=400&h=400&auto=format&fit=crop" alt="Picnic in the park" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Sunday</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-5deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1568901346375-23c9450c58cd?q=80&w=400&h=400&auto=format&fit=crop" alt="Mountain hike above the treeline" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">The climb</figcaption>
</figure>
</div>
</section><section class="tgl-21 w-full min-h-svh grid place-items-center bg-tgl21-bg font-tgl21-sans px-5 py-10 bg-[radial-gradient(rgba(120,100,80,0.14)_1px,transparent_1px)] [background-size:6px_6px]" aria-label="Polaroid stack gallery">
<div class="flex flex-wrap items-center justify-center gap-1.5 w-[min(820px,100%)]">
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-6deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?q=80&w=400&h=400&auto=format&fit=crop" alt="Friends on a summer trip" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Summer '24</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[4deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?q=80&w=400&h=400&auto=format&fit=crop" alt="Sunset on the beach" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Last light</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-3deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1499346030926-9a72daac6c63?q=80&w=400&h=400&auto=format&fit=crop" alt="Road trip stop at a filling station" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Route 1</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[5deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1620121692029-d088224ddc74?q=80&w=400&h=400&auto=format&fit=crop" alt="Picnic in the park" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Sunday</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-5deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1568901346375-23c9450c58cd?q=80&w=400&h=400&auto=format&fit=crop" alt="Mountain hike above the treeline" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">The climb</figcaption>
</figure>
</div>
</section>@import "tailwindcss";
@theme {
--color-tgl21-bg: #d9cfc0;
--color-tgl21-bg: oklch(0.85 0.02 80);
--color-tgl21-print: #fffdf8;
--color-tgl21-print: oklch(0.99 0.006 90);
--color-tgl21-well: #e7e0d4;
--color-tgl21-well: oklch(0.9 0.014 85);
--color-tgl21-ink: #4a3c2c;
--color-tgl21-ink: oklch(0.38 0.03 70);
--color-tgl21-acc: #8a5a2c;
--color-tgl21-acc: oklch(0.5 0.1 60);
--font-tgl21-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgl21-hand: 'Caveat', 'Segoe Script', cursive;
}
.tgl-21 {
width: 100%;
min-height: 100svh;
}
.tgl-21 ::selection {
background: var(--color-tgl21-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tgl21-bg: #d9cfc0;
--color-tgl21-bg: oklch(0.85 0.02 80);
--color-tgl21-print: #fffdf8;
--color-tgl21-print: oklch(0.99 0.006 90);
--color-tgl21-well: #e7e0d4;
--color-tgl21-well: oklch(0.9 0.014 85);
--color-tgl21-ink: #4a3c2c;
--color-tgl21-ink: oklch(0.38 0.03 70);
--color-tgl21-acc: #8a5a2c;
--color-tgl21-acc: oklch(0.5 0.1 60);
--font-tgl21-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgl21-hand: 'Caveat', 'Segoe Script', cursive;
}
.tgl-21 {
width: 100%;
min-height: 100svh;
}
.tgl-21 ::selection {
background: var(--color-tgl21-acc);
color: #fff;
}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-tgl21-bg: #d9cfc0;
--color-tgl21-bg: oklch(0.85 0.02 80);
--color-tgl21-print: #fffdf8;
--color-tgl21-print: oklch(0.99 0.006 90);
--color-tgl21-well: #e7e0d4;
--color-tgl21-well: oklch(0.9 0.014 85);
--color-tgl21-ink: #4a3c2c;
--color-tgl21-ink: oklch(0.38 0.03 70);
--color-tgl21-acc: #8a5a2c;
--color-tgl21-acc: oklch(0.5 0.1 60);
--font-tgl21-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgl21-hand: 'Caveat', 'Segoe Script', cursive;
}
.tgl-21 {
width: 100%;
min-height: 100svh;
}
.tgl-21 ::selection {
background: var(--color-tgl21-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tgl21-bg: #d9cfc0;
--color-tgl21-bg: oklch(0.85 0.02 80);
--color-tgl21-print: #fffdf8;
--color-tgl21-print: oklch(0.99 0.006 90);
--color-tgl21-well: #e7e0d4;
--color-tgl21-well: oklch(0.9 0.014 85);
--color-tgl21-ink: #4a3c2c;
--color-tgl21-ink: oklch(0.38 0.03 70);
--color-tgl21-acc: #8a5a2c;
--color-tgl21-acc: oklch(0.5 0.1 60);
--font-tgl21-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgl21-hand: 'Caveat', 'Segoe Script', cursive;
}
.tgl-21 {
width: 100%;
min-height: 100svh;
}
.tgl-21 ::selection {
background: var(--color-tgl21-acc);
color: #fff;
}<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=Caveat:wght@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=Caveat:wght@500;600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Five
nth-childrotations become one utility per print, which is the difference between a fixed demo and a list a template can render in any order. - The handwriting is now a real webfont token (
--font-tgl21-hand) instead of a'Segoe Script', cursivestack that resolved to a different face on every operating system. - UI change from the CSS original: caption ink darkened from
#5a4a38to a 0.38-lightness token, because a 17px script face at the original value sat just under 4.5:1 on the off-white print.
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 Polaroid Photo Stack Gallery with Rotate-on-Hover
Source: https://codefronts.com/snippets/tailwind-css-image-gallery/tailwind-polaroid-photo-stack-gallery/
Photographs styled as vintage Polaroid prints — thick white frame, deep bottom border, handwritten caption — tossed at casual angles and straightening with a lift as you reach for one. Each print's resting angle is a utility on the print, not an nth-child rule.
## HTML
```html
<section class="tgl-21 w-full min-h-svh grid place-items-center bg-tgl21-bg font-tgl21-sans px-5 py-10 bg-[radial-gradient(rgba(120,100,80,0.14)_1px,transparent_1px)] [background-size:6px_6px]" aria-label="Polaroid stack gallery">
<div class="flex flex-wrap items-center justify-center gap-1.5 w-[min(820px,100%)]">
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-6deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?q=80&w=400&h=400&auto=format&fit=crop" alt="Friends on a summer trip" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Summer '24</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[4deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?q=80&w=400&h=400&auto=format&fit=crop" alt="Sunset on the beach" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Last light</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-3deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1499346030926-9a72daac6c63?q=80&w=400&h=400&auto=format&fit=crop" alt="Road trip stop at a filling station" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Route 1</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[5deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1620121692029-d088224ddc74?q=80&w=400&h=400&auto=format&fit=crop" alt="Picnic in the park" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Sunday</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-5deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1568901346375-23c9450c58cd?q=80&w=400&h=400&auto=format&fit=crop" alt="Mountain hike above the treeline" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">The climb</figcaption>
</figure>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tgl21-bg: #d9cfc0;
--color-tgl21-bg: oklch(0.85 0.02 80);
--color-tgl21-print: #fffdf8;
--color-tgl21-print: oklch(0.99 0.006 90);
--color-tgl21-well: #e7e0d4;
--color-tgl21-well: oklch(0.9 0.014 85);
--color-tgl21-ink: #4a3c2c;
--color-tgl21-ink: oklch(0.38 0.03 70);
--color-tgl21-acc: #8a5a2c;
--color-tgl21-acc: oklch(0.5 0.1 60);
--font-tgl21-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgl21-hand: 'Caveat', 'Segoe Script', cursive;
}
.tgl-21 {
width: 100%;
min-height: 100svh;
}
.tgl-21 ::selection {
background: var(--color-tgl21-acc);
color: #fff;
}
```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 Polaroid Photo Stack Gallery with Rotate-on-Hover
Source: https://codefronts.com/snippets/tailwind-css-image-gallery/tailwind-polaroid-photo-stack-gallery/
Photographs styled as vintage Polaroid prints — thick white frame, deep bottom border, handwritten caption — tossed at casual angles and straightening with a lift as you reach for one. Each print's resting angle is a utility on the print, not an nth-child rule.
## HTML
```html
<section class="tgl-21 w-full min-h-svh grid place-items-center bg-tgl21-bg font-tgl21-sans px-5 py-10 bg-[radial-gradient(rgba(120,100,80,0.14)_1px,transparent_1px)] [background-size:6px_6px]" aria-label="Polaroid stack gallery">
<div class="flex flex-wrap items-center justify-center gap-1.5 w-[min(820px,100%)]">
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-6deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?q=80&w=400&h=400&auto=format&fit=crop" alt="Friends on a summer trip" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Summer '24</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[4deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?q=80&w=400&h=400&auto=format&fit=crop" alt="Sunset on the beach" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Last light</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-3deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1499346030926-9a72daac6c63?q=80&w=400&h=400&auto=format&fit=crop" alt="Road trip stop at a filling station" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Route 1</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[5deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1620121692029-d088224ddc74?q=80&w=400&h=400&auto=format&fit=crop" alt="Picnic in the park" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">Sunday</figcaption>
</figure>
<figure tabindex="0" class="relative m-0 w-[190px] p-3 pb-11 rounded-sm bg-tgl21-print rotate-[-5deg] shadow-[0_10px_24px_-10px_rgba(60,40,20,0.5)] transition-transform duration-[350ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:rotate-0 hover:scale-[1.06] hover:z-[5] hover:shadow-[0_24px_44px_-16px_rgba(60,40,20,0.6)] focus-visible:rotate-0 focus-visible:scale-[1.06] focus-visible:z-[5] focus-visible:outline-3 focus-visible:outline-tgl21-acc focus-visible:outline-offset-4 motion-reduce:transition-none">
<img src="https://images.unsplash.com/photo-1568901346375-23c9450c58cd?q=80&w=400&h=400&auto=format&fit=crop" alt="Mountain hike above the treeline" loading="lazy" decoding="async" class="block w-full aspect-square object-cover bg-tgl21-well sepia-[0.18] contrast-[1.02]">
<figcaption class="mt-3 text-center font-tgl21-hand text-[19px] text-tgl21-ink">The climb</figcaption>
</figure>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tgl21-bg: #d9cfc0;
--color-tgl21-bg: oklch(0.85 0.02 80);
--color-tgl21-print: #fffdf8;
--color-tgl21-print: oklch(0.99 0.006 90);
--color-tgl21-well: #e7e0d4;
--color-tgl21-well: oklch(0.9 0.014 85);
--color-tgl21-ink: #4a3c2c;
--color-tgl21-ink: oklch(0.38 0.03 70);
--color-tgl21-acc: #8a5a2c;
--color-tgl21-acc: oklch(0.5 0.1 60);
--font-tgl21-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgl21-hand: 'Caveat', 'Segoe Script', cursive;
}
.tgl-21 {
width: 100%;
min-height: 100svh;
}
.tgl-21 ::selection {
background: var(--color-tgl21-acc);
color: #fff;
}
```How this works
The frame is padding. Twelve pixels on three sides, forty-four at the foot, on a warm off-white background — that asymmetry is the entire Polaroid signal, and in utilities it is p-3 pb-11.
Angles belong to prints. The CSS version encoded the scatter in five nth-child selectors, which meant reordering the pile rewrote the stylesheet. Here each figure carries its own rotation and the order is free.
Picking one up raises it. hover:z-[5] alongside the straighten, so the active print clears its neighbours instead of sliding under them.
Make it yours
- Scatter: each print's
rotate-[...]value. - Frame depth:
pb-11for a deeper or shallower bottom band. - Overlap the pile with negative margins for a tighter physical stack.
Gotchas — read before shipping
- Raise
z-indexon hover or the lifted print is clipped by the one next to it. - Keep captions as real text, never baked into the image — they are content for both search and screen readers.
focus-visible:must straighten the print too; these aretabindex="0"figures and the keyboard path is the same gesture.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Transforms, filters and shadows are universal; the floor is Tailwind v4's generated sheet.