22 / 36
All 36 in 36 Tailwind Stacked Cards
- 01Tailwind Scroll-Driven Scaling Card Stack
- 02Tailwind Swipe Card Deck Drag to Dismiss
- 03Tailwind Glassmorphism Testimonial Card Stack
- 04Tailwind Stacked Cards Expand Accordion on Click
- 05Tailwind Fan Out Photo Stack on Hover
- 06Tailwind 3D Perspective Tilt Card Stack
- 07Tailwind Multi Step Form Card Stack
- 08Tailwind Tabbed Card Stack Bring to Front
- 09Tailwind Click to Front Stacked Cards Cycle
- 10Tailwind Classic Card Deck Stack Shadow
- 11Tailwind Fan Spread Hand of Cards
- 12Tailwind Polaroid Photo Stack Scattered Rotate
- 13Tailwind Staircase Offset Stacked Cards Cascade
- 14Tailwind Cards Spread Out Horizontally on Hover
- 15Tailwind Stacked Cards Lift on Hover Sibling Push
- 16Tailwind Accordion Stacked Cards Slide Out Menu
- 17Tailwind Shuffle Cards Animation Loop Deck
- 18Tailwind File Folder Tab Stacked Cards
- 19Tailwind Scattered Photos Pinch to Centre on Hover
- 20Tailwind Mobile Swipe Card Stack Translate3d
- 21Tailwind Single Accordion Card Nested Layers
- 22Tailwind Isometric Tower Stacked Cards 3D Column
- 23Tailwind 3D Flip Card Stack Reveal Back
- 24Tailwind Card Stack Tilt on Hover Quadrant
- 25Tailwind Notification Stack Pile Dismiss
- 26Tailwind Receipt Roll Unroll Stacked Items
- 27Tailwind Scratch Card Reveal Canvas Mask
- 28Tailwind Stacked Cards Hover Reveal Spread
- 29Tailwind Scroll Activated Sticky Stacking Cards
- 30Tailwind Stacked Testimonial Slider Radio
- 31Tailwind Isometric Overlapping Stacked Cards
- 32Tailwind Bento Grid Stacked Cards Hover Fan
- 33Tailwind Perspective Card Deck Depth Tunnel
- 34Tailwind Peel Back Corner Card Reveal
- 35Tailwind Timeline Stacked Milestone Cards
- 36Tailwind Spiral Tower Rotating Stacked Cards
Tailwind Isometric Tower Stacked Cards 3D Column
Five floors on a steep isometric plane, each extruded by a before: slab so the column has real thickness. The shading is the interesting port: instead of five colour tokens, each floor computes its own fill from its index inside oklch() — calc(0.78-var(--i)*0.05) in the lightness slot — so the whole tonal ramp is one expression.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="stk-22 w-full min-h-svh flex items-center justify-center px-5 py-[8vh] font-stk22-sans bg-stk22-bg [background-image:radial-gradient(circle_at_50%_30%,var(--color-stk22-glow),transparent_70%)]" aria-label="Isometric tower of cards">
<div class="[perspective:1200px] has-focus-visible:outline-3 has-focus-visible:outline-stk22-ring has-focus-visible:outline-offset-[26px] has-focus-visible:rounded-lg">
<div class="group relative w-50 h-75 outline-none [transform-style:preserve-3d] [transform:rotateX(58deg)_rotateZ(-42deg)]" tabindex="0" aria-hidden="true">
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:0">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Rooftop</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:1">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Sky lounge</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:2">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Offices</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:3">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Atrium</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:4">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Lobby</b>
</div>
</div>
<p class="sr-only">Tower floors, top to bottom: Rooftop, Sky lounge, Offices, Atrium, Lobby.</p>
</div>
</section><section class="stk-22 w-full min-h-svh flex items-center justify-center px-5 py-[8vh] font-stk22-sans bg-stk22-bg [background-image:radial-gradient(circle_at_50%_30%,var(--color-stk22-glow),transparent_70%)]" aria-label="Isometric tower of cards">
<div class="[perspective:1200px] has-focus-visible:outline-3 has-focus-visible:outline-stk22-ring has-focus-visible:outline-offset-[26px] has-focus-visible:rounded-lg">
<div class="group relative w-50 h-75 outline-none [transform-style:preserve-3d] [transform:rotateX(58deg)_rotateZ(-42deg)]" tabindex="0" aria-hidden="true">
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:0">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Rooftop</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:1">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Sky lounge</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:2">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Offices</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:3">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Atrium</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:4">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Lobby</b>
</div>
</div>
<p class="sr-only">Tower floors, top to bottom: Rooftop, Sky lounge, Offices, Atrium, Lobby.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-stk22-bg: #0a0d15;
--color-stk22-bg: oklch(0.13 0.016 265);
--color-stk22-glow: #1a2030;
--color-stk22-glow: oklch(0.24 0.026 265);
--color-stk22-ring: #7fb2e8;
--color-stk22-ring: oklch(0.70 0.12 240);
--font-stk22-sans: 'Archivo', system-ui, sans-serif;
--ease-stk22: cubic-bezier(0.3, 0.9, 0.3, 1);
}@import "tailwindcss";
@theme {
--color-stk22-bg: #0a0d15;
--color-stk22-bg: oklch(0.13 0.016 265);
--color-stk22-glow: #1a2030;
--color-stk22-glow: oklch(0.24 0.026 265);
--color-stk22-ring: #7fb2e8;
--color-stk22-ring: oklch(0.70 0.12 240);
--font-stk22-sans: 'Archivo', system-ui, sans-serif;
--ease-stk22: cubic-bezier(0.3, 0.9, 0.3, 1);
}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-stk22-bg: #0a0d15;
--color-stk22-bg: oklch(0.13 0.016 265);
--color-stk22-glow: #1a2030;
--color-stk22-glow: oklch(0.24 0.026 265);
--color-stk22-ring: #7fb2e8;
--color-stk22-ring: oklch(0.70 0.12 240);
--font-stk22-sans: 'Archivo', system-ui, sans-serif;
--ease-stk22: cubic-bezier(0.3, 0.9, 0.3, 1);
}@import "tailwindcss";
@theme {
--color-stk22-bg: #0a0d15;
--color-stk22-bg: oklch(0.13 0.016 265);
--color-stk22-glow: #1a2030;
--color-stk22-glow: oklch(0.24 0.026 265);
--color-stk22-ring: #7fb2e8;
--color-stk22-ring: oklch(0.70 0.12 240);
--font-stk22-sans: 'Archivo', system-ui, sans-serif;
--ease-stk22: cubic-bezier(0.3, 0.9, 0.3, 1);
}<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=Archivo:wdth,wght@75..125,400;75..125,800&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@75..125,400;75..125,800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The webfonts load as
<link>tags insetup, not as an@importinside the stylesheet. Tailwind emits user@importrules after its own@layerblocks, and a late@importis invalid CSS — the browser drops it and the demo silently falls back to system fonts. - The tonal ramp is computed inside
oklch()from the floor index, so five fills come from one arbitrary background — and because oklch lightness is perceptually uniform, the steps look even. - The extrusion is a
before:utility chain, including its ownbefore:[transform:translateZ(-34px)], so the slab that gives each floor thickness is declared on the floor. - Depth and its hover expansion are the same expression with different multipliers, exactly as in demo 10 — the index pattern again, on the Z axis.
[perspective:1200px]on the scene and[transform-style:preserve-3d]on the column: three arbitrary properties, all of them correct as arbitrary properties.- The whole scene is
aria-hiddenwith ansr-onlyfloor list beside it — a foreshortened 3D diagram is a picture of information, not the information. - The focus ring lives on a wrapper outside the 3D context; inside it, an outline would be rotated and squashed with the tower.
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 Isometric Tower Stacked Cards 3D Column
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-isometric-tower-stacked-cards-3d-column/
Five floors on a steep isometric plane, each extruded by a before: slab so the column has real thickness. The shading is the interesting port: instead of five colour tokens, each floor computes its own fill from its index inside oklch() — calc(0.78-var(--i)*0.05) in the lightness slot — so the whole tonal ramp is one expression.
## HTML
```html
<section class="stk-22 w-full min-h-svh flex items-center justify-center px-5 py-[8vh] font-stk22-sans bg-stk22-bg [background-image:radial-gradient(circle_at_50%_30%,var(--color-stk22-glow),transparent_70%)]" aria-label="Isometric tower of cards">
<div class="[perspective:1200px] has-focus-visible:outline-3 has-focus-visible:outline-stk22-ring has-focus-visible:outline-offset-[26px] has-focus-visible:rounded-lg">
<div class="group relative w-50 h-75 outline-none [transform-style:preserve-3d] [transform:rotateX(58deg)_rotateZ(-42deg)]" tabindex="0" aria-hidden="true">
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:0">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Rooftop</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:1">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Sky lounge</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:2">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Offices</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:3">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Atrium</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:4">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Lobby</b>
</div>
</div>
<p class="sr-only">Tower floors, top to bottom: Rooftop, Sky lounge, Offices, Atrium, Lobby.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk22-bg: #0a0d15;
--color-stk22-bg: oklch(0.13 0.016 265);
--color-stk22-glow: #1a2030;
--color-stk22-glow: oklch(0.24 0.026 265);
--color-stk22-ring: #7fb2e8;
--color-stk22-ring: oklch(0.70 0.12 240);
--font-stk22-sans: 'Archivo', system-ui, sans-serif;
--ease-stk22: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```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 Isometric Tower Stacked Cards 3D Column
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-isometric-tower-stacked-cards-3d-column/
Five floors on a steep isometric plane, each extruded by a before: slab so the column has real thickness. The shading is the interesting port: instead of five colour tokens, each floor computes its own fill from its index inside oklch() — calc(0.78-var(--i)*0.05) in the lightness slot — so the whole tonal ramp is one expression.
## HTML
```html
<section class="stk-22 w-full min-h-svh flex items-center justify-center px-5 py-[8vh] font-stk22-sans bg-stk22-bg [background-image:radial-gradient(circle_at_50%_30%,var(--color-stk22-glow),transparent_70%)]" aria-label="Isometric tower of cards">
<div class="[perspective:1200px] has-focus-visible:outline-3 has-focus-visible:outline-stk22-ring has-focus-visible:outline-offset-[26px] has-focus-visible:rounded-lg">
<div class="group relative w-50 h-75 outline-none [transform-style:preserve-3d] [transform:rotateX(58deg)_rotateZ(-42deg)]" tabindex="0" aria-hidden="true">
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:0">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Rooftop</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:1">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Sky lounge</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:2">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Offices</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:3">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Atrium</b>
</div>
<div class="absolute left-0 top-0 flex size-45 items-center justify-center rounded-[10px] p-3.5 shadow-[0_20px_30px_-16px_rgba(0,0,0,0.6)] [background-image:linear-gradient(160deg,oklch(calc(0.78-var(--i)*0.05)_0.09_240),oklch(calc(0.64-var(--i)*0.05)_0.11_250))] [transform:translateZ(calc(var(--i)*34px))] before:absolute before:left-0 before:bottom-0 before:h-8.5 before:w-full before:rounded-b-[10px] before:[background:oklch(calc(0.5-var(--i)*0.04)_0.1_250)] before:[transform:translateZ(-34px)] transition-transform duration-500 ease-stk22 group-hover:[transform:translateZ(calc(var(--i)*60px+10px))] group-focus-visible:[transform:translateZ(calc(var(--i)*60px+10px))] motion-reduce:transition-none" style="--i:4">
<b class="text-center text-[15px] font-extrabold tracking-[0.02em] text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.45)]">Lobby</b>
</div>
</div>
<p class="sr-only">Tower floors, top to bottom: Rooftop, Sky lounge, Offices, Atrium, Lobby.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk22-bg: #0a0d15;
--color-stk22-bg: oklch(0.13 0.016 265);
--color-stk22-glow: #1a2030;
--color-stk22-glow: oklch(0.24 0.026 265);
--color-stk22-ring: #7fb2e8;
--color-stk22-ring: oklch(0.70 0.12 240);
--font-stk22-sans: 'Archivo', system-ui, sans-serif;
--ease-stk22: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```How this works
The tonal ramp is arithmetic in the colour function. Five floors need five fills, and the CSS version writes them as one gradient per floor with the index in the lightness channel. Utilities can do the same thing, once:
[background-image:linear-gradient(160deg,
oklch(calc(0.78-var(--i)*0.05)_0.09_240),
oklch(calc(0.64-var(--i)*0.05)_0.11_250))]This is why oklch() matters beyond taste: because its lightness channel is perceptually uniform, subtracting a constant per floor gives visually even steps. Doing the same in hsl() produces a ramp that looks bunched at one end.
Perspective on the parent, always. [perspective:1200px] on the scene; [transform-style:preserve-3d] plus the isometric rotation on the column. The same rule as demo 06, and the same failure mode if you swap them.
Thickness comes from a pseudo-element. Each floor's before: slab sits at translateZ(-34px) — exactly the floor spacing — so the gap between floors is filled and the column reads as solid rather than as five hovering plates.
Decorative 3D needs a text equivalent. The scene is aria-hidden and a plain sr-only list names the floors in order. A rotated, foreshortened diagram is a picture of information; the information itself should also exist as text.
Make it yours
- Change the tower's angle via the shared
rotateX(58deg)_rotateZ(-42deg). - Set floor spacing with the
34pxin the translate and match the extrusion slab's-34pxand height. - Steepen the tonal ramp by changing the
0.05lightness step. - Widen the hover separation with the
60pxmultiplier. - Add a floor with the next
--i; the fill and depth both follow from it.
Gotchas — read before shipping
perspectivebelongs on the parent scene. On the rotating column it flattens the 3D into a 2D skew.- The extrusion slab's
translateZmust equal the floor spacing, or you get either gaps or overlap. - Order the floors so overlaps paint correctly; in a
preserve-3dcontext source order still breaks ties between coplanar surfaces. - Give the scene vertical room. A rotated column is taller than its unrotated box and clips silently.
- Put the focus ring outside the 3D context; inside it, an outline is rotated and foreshortened along with everything else.
- Mark the scene
aria-hiddenand provide the floor names as text. A 3D diagram is not a substitute for content.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
3D transforms and preserve-3d are broadly supported (Chrome 36+, Safari 9+, Firefox 16+); oklch() needs Chrome 111+, Safari 15.4+, Firefox 113+, which is inside Tailwind v4's own floor anyway.