10 CSS Parallax Effects 08 / 10
CSS Parallax Card Hover Effect
Six product/profile cards where three independent layers — gradient background, geometric SVG decoration, text content — shift on mouse position at 8px, 14px, and 22px depth respectively.
This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.
The code
<div class="plx-08">
<header class="plx-08__header">
<p class="plx-08__label">CSS Parallax · Mouse-Driven Tilt</p>
<h1>Hover over a card<br><span>— any card.</span></h1>
</header>
<div class="plx-08__grid">
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<circle cx="250" cy="80" r="120" stroke="white" stroke-width="1" fill="none"/>
<circle cx="250" cy="80" r="70" stroke="white" stroke-width="0.5" fill="none"/>
<line x1="0" y1="440" x2="300" y2="0" stroke="white" stroke-width="0.4"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">🌌</div>
<p class="plx-08__card-tag">01 · Astrophysics</p>
<h3 class="plx-08__card-title">The Observable Universe</h3>
<p class="plx-08__card-body">93 billion light-years of space. Everything we know, everything we can ever know, fits inside this sphere.</p>
<span class="plx-08__card-cta">Explore</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<polygon points="150,20 280,380 20,380" stroke="white" stroke-width="1" fill="none"/>
<polygon points="150,80 240,340 60,340" stroke="white" stroke-width="0.5" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">💎</div>
<p class="plx-08__card-tag">02 · Mineralogy</p>
<h3 class="plx-08__card-title">Crystalline Structures</h3>
<p class="plx-08__card-body">Carbon under immense pressure becomes diamond. Chaos compressed into the most ordered thing in nature.</p>
<span class="plx-08__card-cta">Discover</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<path d="M0,220 Q75,100 150,220 Q225,340 300,220" stroke="white" stroke-width="1" fill="none"/>
<path d="M0,220 Q75,140 150,220 Q225,300 300,220" stroke="white" stroke-width="0.5" fill="none"/>
<path d="M0,220 Q75,180 150,220 Q225,260 300,220" stroke="white" stroke-width="0.3" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">🌊</div>
<p class="plx-08__card-tag">03 · Oceanography</p>
<h3 class="plx-08__card-title">Deep Currents</h3>
<p class="plx-08__card-body">The ocean's thermohaline circulation moves water around the entire planet over hundreds of years.</p>
<span class="plx-08__card-cta">Dive in</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<rect x="30" y="30" width="240" height="380" rx="20" stroke="white" stroke-width="1" fill="none"/>
<rect x="70" y="70" width="160" height="300" rx="10" stroke="white" stroke-width="0.5" fill="none"/>
<rect x="110" y="110" width="80" height="220" rx="5" stroke="white" stroke-width="0.3" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">🏙️</div>
<p class="plx-08__card-tag">04 · Architecture</p>
<h3 class="plx-08__card-title">Vertical Cities</h3>
<p class="plx-08__card-body">When land is scarce and ambition isn't, we build upward. The skyline is a city's autobiography.</p>
<span class="plx-08__card-cta">Ascend</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<circle cx="150" cy="220" r="160" stroke="white" stroke-width="1" fill="none" stroke-dasharray="8 6"/>
<circle cx="150" cy="220" r="100" stroke="white" stroke-width="0.5" fill="none" stroke-dasharray="5 4"/>
<circle cx="150" cy="220" r="40" stroke="white" stroke-width="0.3" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">⚡</div>
<p class="plx-08__card-tag">05 · Physics</p>
<h3 class="plx-08__card-title">Electromagnetic Fields</h3>
<p class="plx-08__card-body">Invisible forces that hold atoms together, power every device, and fill every cubic inch of space around you.</p>
<span class="plx-08__card-cta">Charge up</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<path d="M20,400 Q80,200 150,100 Q220,0 280,100 Q350,200 150,400" stroke="white" stroke-width="1" fill="none"/>
<path d="M60,400 Q100,250 150,160 Q200,80 250,200 Q280,300 150,400" stroke="white" stroke-width="0.4" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">🌿</div>
<p class="plx-08__card-tag">06 · Botany</p>
<h3 class="plx-08__card-title">Fractal Growth</h3>
<p class="plx-08__card-body">A fern leaf, a river delta, a bolt of lightning — nature repeats its favourite shapes at every scale.</p>
<span class="plx-08__card-cta">Grow</span>
</div>
</div>
</div>
<p class="plx-08__footer">Hover any card · 3 independent parallax layers · CSS transform + JS cursor</p>
</div> <div class="plx-08">
<header class="plx-08__header">
<p class="plx-08__label">CSS Parallax · Mouse-Driven Tilt</p>
<h1>Hover over a card<br><span>— any card.</span></h1>
</header>
<div class="plx-08__grid">
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<circle cx="250" cy="80" r="120" stroke="white" stroke-width="1" fill="none"/>
<circle cx="250" cy="80" r="70" stroke="white" stroke-width="0.5" fill="none"/>
<line x1="0" y1="440" x2="300" y2="0" stroke="white" stroke-width="0.4"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">🌌</div>
<p class="plx-08__card-tag">01 · Astrophysics</p>
<h3 class="plx-08__card-title">The Observable Universe</h3>
<p class="plx-08__card-body">93 billion light-years of space. Everything we know, everything we can ever know, fits inside this sphere.</p>
<span class="plx-08__card-cta">Explore</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<polygon points="150,20 280,380 20,380" stroke="white" stroke-width="1" fill="none"/>
<polygon points="150,80 240,340 60,340" stroke="white" stroke-width="0.5" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">💎</div>
<p class="plx-08__card-tag">02 · Mineralogy</p>
<h3 class="plx-08__card-title">Crystalline Structures</h3>
<p class="plx-08__card-body">Carbon under immense pressure becomes diamond. Chaos compressed into the most ordered thing in nature.</p>
<span class="plx-08__card-cta">Discover</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<path d="M0,220 Q75,100 150,220 Q225,340 300,220" stroke="white" stroke-width="1" fill="none"/>
<path d="M0,220 Q75,140 150,220 Q225,300 300,220" stroke="white" stroke-width="0.5" fill="none"/>
<path d="M0,220 Q75,180 150,220 Q225,260 300,220" stroke="white" stroke-width="0.3" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">🌊</div>
<p class="plx-08__card-tag">03 · Oceanography</p>
<h3 class="plx-08__card-title">Deep Currents</h3>
<p class="plx-08__card-body">The ocean's thermohaline circulation moves water around the entire planet over hundreds of years.</p>
<span class="plx-08__card-cta">Dive in</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<rect x="30" y="30" width="240" height="380" rx="20" stroke="white" stroke-width="1" fill="none"/>
<rect x="70" y="70" width="160" height="300" rx="10" stroke="white" stroke-width="0.5" fill="none"/>
<rect x="110" y="110" width="80" height="220" rx="5" stroke="white" stroke-width="0.3" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">🏙️</div>
<p class="plx-08__card-tag">04 · Architecture</p>
<h3 class="plx-08__card-title">Vertical Cities</h3>
<p class="plx-08__card-body">When land is scarce and ambition isn't, we build upward. The skyline is a city's autobiography.</p>
<span class="plx-08__card-cta">Ascend</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<circle cx="150" cy="220" r="160" stroke="white" stroke-width="1" fill="none" stroke-dasharray="8 6"/>
<circle cx="150" cy="220" r="100" stroke="white" stroke-width="0.5" fill="none" stroke-dasharray="5 4"/>
<circle cx="150" cy="220" r="40" stroke="white" stroke-width="0.3" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">⚡</div>
<p class="plx-08__card-tag">05 · Physics</p>
<h3 class="plx-08__card-title">Electromagnetic Fields</h3>
<p class="plx-08__card-body">Invisible forces that hold atoms together, power every device, and fill every cubic inch of space around you.</p>
<span class="plx-08__card-cta">Charge up</span>
</div>
</div>
<div class="plx-08__card">
<div class="plx-08__card-bg"></div>
<div class="plx-08__card-light"></div>
<div class="plx-08__card-noise"></div>
<div class="plx-08__card-geo">
<svg viewBox="0 0 300 440" xmlns="http://www.w3.org/2000/svg">
<path d="M20,400 Q80,200 150,100 Q220,0 280,100 Q350,200 150,400" stroke="white" stroke-width="1" fill="none"/>
<path d="M60,400 Q100,250 150,160 Q200,80 250,200 Q280,300 150,400" stroke="white" stroke-width="0.4" fill="none"/>
</svg>
</div>
<div class="plx-08__card-content">
<div class="plx-08__card-icon">🌿</div>
<p class="plx-08__card-tag">06 · Botany</p>
<h3 class="plx-08__card-title">Fractal Growth</h3>
<p class="plx-08__card-body">A fern leaf, a river delta, a bolt of lightning — nature repeats its favourite shapes at every scale.</p>
<span class="plx-08__card-cta">Grow</span>
</div>
</div>
</div>
<p class="plx-08__footer">Hover any card · 3 independent parallax layers · CSS transform + JS cursor</p>
</div>*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* Fall back to system mono if Geist unavailable */
.plx-08 {
--bg: #0c0c10;
--surface: #14141c;
--border: rgba(255,255,255,0.08);
--text: #e8e8f0;
--muted: rgba(232,232,240,0.45);
--card-h: 440px;
background: var(--bg);
color: var(--text);
font-family: 'Geist', system-ui, sans-serif;
min-height: 100vh;
padding: 60px 40px;
}
/* Header */
.plx-08__header {
text-align: center;
margin-bottom: 80px;
}
.plx-08__label {
display: inline-block;
font-size: 10px;
font-family: 'Geist Mono', monospace;
letter-spacing: 0.3em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 16px;
}
.plx-08__header h1 {
font-size: clamp(32px, 5vw, 60px);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.0;
}
.plx-08__header h1 span {
opacity: 0.3;
}
/* Grid */
.plx-08__grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 24px;
max-width: 1200px;
margin: 0 auto;
}
/* === THE CARD === */
.plx-08__card {
position: relative;
height: var(--card-h);
border-radius: 16px;
border: 1px solid var(--border);
overflow: hidden;
cursor: pointer;
transform-style: preserve-3d;
will-change: transform;
/* 3D perspective is set inline via JS */
transform: perspective(800px) rotateX(0deg) rotateY(0deg);
transition: transform 0.1s ease, box-shadow 0.3s ease;
}
.plx-08__card:not(:hover) {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.6s ease;
}
/* Background gradient layer — moves slower than card tilt */
.plx-08__card-bg {
position: absolute;
inset: -10%;
border-radius: 24px;
will-change: transform;
transition: transform 0.1s ease;
transform: translateX(0px) translateY(0px);
}
.plx-08__card:not(:hover) .plx-08__card-bg {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Card accent/color themes */
.plx-08__card:nth-child(1) .plx-08__card-bg { background: radial-gradient(ellipse at 40% 40%, rgba(99,102,241,0.6) 0%, rgba(30,27,75,0.9) 60%); }
.plx-08__card:nth-child(2) .plx-08__card-bg { background: radial-gradient(ellipse at 60% 40%, rgba(236,72,153,0.5) 0%, rgba(75,10,50,0.9) 60%); }
.plx-08__card:nth-child(3) .plx-08__card-bg { background: radial-gradient(ellipse at 40% 60%, rgba(16,185,129,0.5) 0%, rgba(5,50,30,0.9) 60%); }
.plx-08__card:nth-child(4) .plx-08__card-bg { background: radial-gradient(ellipse at 50% 40%, rgba(245,158,11,0.5) 0%, rgba(60,30,5,0.9) 60%); }
.plx-08__card:nth-child(5) .plx-08__card-bg { background: radial-gradient(ellipse at 60% 60%, rgba(14,165,233,0.5) 0%, rgba(5,30,60,0.9) 60%); }
.plx-08__card:nth-child(6) .plx-08__card-bg { background: radial-gradient(ellipse at 40% 40%, rgba(168,85,247,0.5) 0%, rgba(40,10,70,0.9) 60%); }
/* Shimmer/light layer */
.plx-08__card-light {
position: absolute;
inset: 0;
background: radial-gradient(circle at 50% 50%, rgba(255,255,255,0.12) 0%, transparent 60%);
will-change: background;
pointer-events: none;
transition: background 0.1s ease;
border-radius: inherit;
}
/* Noise texture */
.plx-08__card-noise {
position: absolute;
inset: 0;
opacity: 0.04;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
pointer-events: none;
}
/* Geometric decorative layer — moves opposite to BG */
.plx-08__card-geo {
position: absolute;
inset: 0;
will-change: transform;
transform: translateX(0px) translateY(0px);
transition: transform 0.1s ease;
pointer-events: none;
}
.plx-08__card:not(:hover) .plx-08__card-geo {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.plx-08__card-geo svg {
width: 100%; height: 100%;
opacity: 0.18;
}
/* Content layer — moves even more than card tilt (depth pop) */
.plx-08__card-content {
position: absolute;
inset: 0;
padding: 32px;
display: flex;
flex-direction: column;
justify-content: flex-end;
will-change: transform;
transform: translateX(0px) translateY(0px) translateZ(0px);
transition: transform 0.1s ease;
z-index: 5;
}
.plx-08__card:not(:hover) .plx-08__card-content {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.plx-08__card-icon {
width: 48px;
height: 48px;
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.15);
background: rgba(255,255,255,0.08);
display: grid;
place-items: center;
font-size: 22px;
margin-bottom: auto;
}
.plx-08__card-tag {
font-family: 'Geist Mono', monospace;
font-size: 10px;
letter-spacing: 0.2em;
text-transform: uppercase;
opacity: 0.4;
margin-bottom: 10px;
}
.plx-08__card-title {
font-size: 22px;
font-weight: 700;
letter-spacing: -0.02em;
line-height: 1.2;
margin-bottom: 10px;
}
.plx-08__card-body {
font-size: 13px;
font-weight: 300;
line-height: 1.65;
opacity: 0.55;
margin-bottom: 24px;
}
.plx-08__card-cta {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
font-weight: 500;
font-family: 'Geist Mono', monospace;
letter-spacing: 0.08em;
opacity: 0.7;
transition: opacity 0.2s;
}
.plx-08__card:hover .plx-08__card-cta { opacity: 1; }
.plx-08__card-cta::after {
content: '→';
transition: transform 0.2s;
}
.plx-08__card:hover .plx-08__card-cta::after { transform: translateX(4px); }
/* Shadow ring on hover */
.plx-08__card:hover {
box-shadow:
0 20px 60px rgba(0,0,0,0.5),
0 0 0 1px rgba(255,255,255,0.12);
}
/* Footer note */
.plx-08__footer {
text-align: center;
margin-top: 60px;
font-family: 'Geist Mono', monospace;
font-size: 11px;
letter-spacing: 0.15em;
color: var(--muted);
}
@media (max-width: 600px) {
.plx-08 { padding: 40px 20px; }
.plx-08__grid { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
.plx-08__card { transition: none !important; transform: none !important; }
.plx-08__card-bg, .plx-08__card-geo, .plx-08__card-content { transition: none !important; transform: none !important; }
} *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* Fall back to system mono if Geist unavailable */
.plx-08 {
--bg: #0c0c10;
--surface: #14141c;
--border: rgba(255,255,255,0.08);
--text: #e8e8f0;
--muted: rgba(232,232,240,0.45);
--card-h: 440px;
background: var(--bg);
color: var(--text);
font-family: 'Geist', system-ui, sans-serif;
min-height: 100vh;
padding: 60px 40px;
}
/* Header */
.plx-08__header {
text-align: center;
margin-bottom: 80px;
}
.plx-08__label {
display: inline-block;
font-size: 10px;
font-family: 'Geist Mono', monospace;
letter-spacing: 0.3em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 16px;
}
.plx-08__header h1 {
font-size: clamp(32px, 5vw, 60px);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.0;
}
.plx-08__header h1 span {
opacity: 0.3;
}
/* Grid */
.plx-08__grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 24px;
max-width: 1200px;
margin: 0 auto;
}
/* === THE CARD === */
.plx-08__card {
position: relative;
height: var(--card-h);
border-radius: 16px;
border: 1px solid var(--border);
overflow: hidden;
cursor: pointer;
transform-style: preserve-3d;
will-change: transform;
/* 3D perspective is set inline via JS */
transform: perspective(800px) rotateX(0deg) rotateY(0deg);
transition: transform 0.1s ease, box-shadow 0.3s ease;
}
.plx-08__card:not(:hover) {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.6s ease;
}
/* Background gradient layer — moves slower than card tilt */
.plx-08__card-bg {
position: absolute;
inset: -10%;
border-radius: 24px;
will-change: transform;
transition: transform 0.1s ease;
transform: translateX(0px) translateY(0px);
}
.plx-08__card:not(:hover) .plx-08__card-bg {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Card accent/color themes */
.plx-08__card:nth-child(1) .plx-08__card-bg { background: radial-gradient(ellipse at 40% 40%, rgba(99,102,241,0.6) 0%, rgba(30,27,75,0.9) 60%); }
.plx-08__card:nth-child(2) .plx-08__card-bg { background: radial-gradient(ellipse at 60% 40%, rgba(236,72,153,0.5) 0%, rgba(75,10,50,0.9) 60%); }
.plx-08__card:nth-child(3) .plx-08__card-bg { background: radial-gradient(ellipse at 40% 60%, rgba(16,185,129,0.5) 0%, rgba(5,50,30,0.9) 60%); }
.plx-08__card:nth-child(4) .plx-08__card-bg { background: radial-gradient(ellipse at 50% 40%, rgba(245,158,11,0.5) 0%, rgba(60,30,5,0.9) 60%); }
.plx-08__card:nth-child(5) .plx-08__card-bg { background: radial-gradient(ellipse at 60% 60%, rgba(14,165,233,0.5) 0%, rgba(5,30,60,0.9) 60%); }
.plx-08__card:nth-child(6) .plx-08__card-bg { background: radial-gradient(ellipse at 40% 40%, rgba(168,85,247,0.5) 0%, rgba(40,10,70,0.9) 60%); }
/* Shimmer/light layer */
.plx-08__card-light {
position: absolute;
inset: 0;
background: radial-gradient(circle at 50% 50%, rgba(255,255,255,0.12) 0%, transparent 60%);
will-change: background;
pointer-events: none;
transition: background 0.1s ease;
border-radius: inherit;
}
/* Noise texture */
.plx-08__card-noise {
position: absolute;
inset: 0;
opacity: 0.04;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
pointer-events: none;
}
/* Geometric decorative layer — moves opposite to BG */
.plx-08__card-geo {
position: absolute;
inset: 0;
will-change: transform;
transform: translateX(0px) translateY(0px);
transition: transform 0.1s ease;
pointer-events: none;
}
.plx-08__card:not(:hover) .plx-08__card-geo {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.plx-08__card-geo svg {
width: 100%; height: 100%;
opacity: 0.18;
}
/* Content layer — moves even more than card tilt (depth pop) */
.plx-08__card-content {
position: absolute;
inset: 0;
padding: 32px;
display: flex;
flex-direction: column;
justify-content: flex-end;
will-change: transform;
transform: translateX(0px) translateY(0px) translateZ(0px);
transition: transform 0.1s ease;
z-index: 5;
}
.plx-08__card:not(:hover) .plx-08__card-content {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.plx-08__card-icon {
width: 48px;
height: 48px;
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.15);
background: rgba(255,255,255,0.08);
display: grid;
place-items: center;
font-size: 22px;
margin-bottom: auto;
}
.plx-08__card-tag {
font-family: 'Geist Mono', monospace;
font-size: 10px;
letter-spacing: 0.2em;
text-transform: uppercase;
opacity: 0.4;
margin-bottom: 10px;
}
.plx-08__card-title {
font-size: 22px;
font-weight: 700;
letter-spacing: -0.02em;
line-height: 1.2;
margin-bottom: 10px;
}
.plx-08__card-body {
font-size: 13px;
font-weight: 300;
line-height: 1.65;
opacity: 0.55;
margin-bottom: 24px;
}
.plx-08__card-cta {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
font-weight: 500;
font-family: 'Geist Mono', monospace;
letter-spacing: 0.08em;
opacity: 0.7;
transition: opacity 0.2s;
}
.plx-08__card:hover .plx-08__card-cta { opacity: 1; }
.plx-08__card-cta::after {
content: '→';
transition: transform 0.2s;
}
.plx-08__card:hover .plx-08__card-cta::after { transform: translateX(4px); }
/* Shadow ring on hover */
.plx-08__card:hover {
box-shadow:
0 20px 60px rgba(0,0,0,0.5),
0 0 0 1px rgba(255,255,255,0.12);
}
/* Footer note */
.plx-08__footer {
text-align: center;
margin-top: 60px;
font-family: 'Geist Mono', monospace;
font-size: 11px;
letter-spacing: 0.15em;
color: var(--muted);
}
@media (max-width: 600px) {
.plx-08 { padding: 40px 20px; }
.plx-08__grid { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
.plx-08__card { transition: none !important; transform: none !important; }
.plx-08__card-bg, .plx-08__card-geo, .plx-08__card-content { transition: none !important; transform: none !important; }
}(() => {
const root = document.querySelector('.plx-08');
if (!root) return;
const cards = Array.from(root.querySelectorAll('.plx-08__card'));
const TILT_MAX = 18; // degrees
const BG_SPEED = 0.3;
const GEO_SPEED = -0.5;
const CONTENT_SPEED = 0.7;
cards.forEach(card => {
const bg = card.querySelector('.plx-08__card-bg');
const light = card.querySelector('.plx-08__card-light');
const geo = card.querySelector('.plx-08__card-geo');
const content = card.querySelector('.plx-08__card-content');
function onMove(e) {
const rect = card.getBoundingClientRect();
// Normalized position: -1 to 1
const nx = ((e.clientX - rect.left) / rect.width) * 2 - 1;
const ny = ((e.clientY - rect.top) / rect.height) * 2 - 1;
// Card tilt
const rotX = -ny * TILT_MAX;
const rotY = nx * TILT_MAX;
card.style.transform = `perspective(800px) rotateX(${rotX}deg) rotateY(${rotY}deg)`;
// BG drifts slowly in same direction
const bgX = nx * 20 * BG_SPEED;
const bgY = ny * 20 * BG_SPEED;
if (bg) bg.style.transform = `translateX(${bgX}px) translateY(${bgY}px)`;
// Light follows cursor
if (light) light.style.background = `radial-gradient(circle at ${(nx+1)/2*100}% ${(ny+1)/2*100}%, rgba(255,255,255,0.15) 0%, transparent 55%)`;
// Geo drifts in opposite direction (depth separation)
const geoX = nx * 20 * GEO_SPEED;
const geoY = ny * 20 * GEO_SPEED;
if (geo) geo.style.transform = `translateX(${geoX}px) translateY(${geoY}px)`;
// Content pops forward
const contentX = nx * 12 * CONTENT_SPEED;
const contentY = ny * 12 * CONTENT_SPEED;
if (content) content.style.transform = `translateX(${contentX}px) translateY(${contentY}px) translateZ(20px)`;
}
function onLeave() {
card.style.transform = 'perspective(800px) rotateX(0deg) rotateY(0deg)';
if (bg) bg.style.transform = 'translateX(0px) translateY(0px)';
if (geo) geo.style.transform = 'translateX(0px) translateY(0px)';
if (content) content.style.transform = 'translateX(0px) translateY(0px) translateZ(0px)';
if (light) light.style.background = 'radial-gradient(circle at 50% 50%, rgba(255,255,255,0.12) 0%, transparent 60%)';
}
// Touch support
function onTouch(e) {
const t = e.touches[0];
onMove({ clientX: t.clientX, clientY: t.clientY });
}
card.addEventListener('mousemove', onMove);
card.addEventListener('mouseleave', onLeave);
card.addEventListener('touchmove', onTouch, { passive: true });
card.addEventListener('touchend', onLeave);
});
})(); (() => {
const root = document.querySelector('.plx-08');
if (!root) return;
const cards = Array.from(root.querySelectorAll('.plx-08__card'));
const TILT_MAX = 18; // degrees
const BG_SPEED = 0.3;
const GEO_SPEED = -0.5;
const CONTENT_SPEED = 0.7;
cards.forEach(card => {
const bg = card.querySelector('.plx-08__card-bg');
const light = card.querySelector('.plx-08__card-light');
const geo = card.querySelector('.plx-08__card-geo');
const content = card.querySelector('.plx-08__card-content');
function onMove(e) {
const rect = card.getBoundingClientRect();
// Normalized position: -1 to 1
const nx = ((e.clientX - rect.left) / rect.width) * 2 - 1;
const ny = ((e.clientY - rect.top) / rect.height) * 2 - 1;
// Card tilt
const rotX = -ny * TILT_MAX;
const rotY = nx * TILT_MAX;
card.style.transform = `perspective(800px) rotateX(${rotX}deg) rotateY(${rotY}deg)`;
// BG drifts slowly in same direction
const bgX = nx * 20 * BG_SPEED;
const bgY = ny * 20 * BG_SPEED;
if (bg) bg.style.transform = `translateX(${bgX}px) translateY(${bgY}px)`;
// Light follows cursor
if (light) light.style.background = `radial-gradient(circle at ${(nx+1)/2*100}% ${(ny+1)/2*100}%, rgba(255,255,255,0.15) 0%, transparent 55%)`;
// Geo drifts in opposite direction (depth separation)
const geoX = nx * 20 * GEO_SPEED;
const geoY = ny * 20 * GEO_SPEED;
if (geo) geo.style.transform = `translateX(${geoX}px) translateY(${geoY}px)`;
// Content pops forward
const contentX = nx * 12 * CONTENT_SPEED;
const contentY = ny * 12 * CONTENT_SPEED;
if (content) content.style.transform = `translateX(${contentX}px) translateY(${contentY}px) translateZ(20px)`;
}
function onLeave() {
card.style.transform = 'perspective(800px) rotateX(0deg) rotateY(0deg)';
if (bg) bg.style.transform = 'translateX(0px) translateY(0px)';
if (geo) geo.style.transform = 'translateX(0px) translateY(0px)';
if (content) content.style.transform = 'translateX(0px) translateY(0px) translateZ(0px)';
if (light) light.style.background = 'radial-gradient(circle at 50% 50%, rgba(255,255,255,0.12) 0%, transparent 60%)';
}
// Touch support
function onTouch(e) {
const t = e.touches[0];
onMove({ clientX: t.clientX, clientY: t.clientY });
}
card.addEventListener('mousemove', onMove);
card.addEventListener('mouseleave', onLeave);
card.addEventListener('touchmove', onTouch, { passive: true });
card.addEventListener('touchend', onLeave);
});
})();More from 10 CSS Parallax Effects
CSS Parallax Image Grid / GalleryCSS Horizontal Parallax ScrollCSS Parallax Text Overlay EffectCSS Zoom-In / Depth Parallax on ScrollCSS Parallax Background Blur TransitionCSS Parallax Hero SectionMulti-layered CSS Parallax Landscape / IllustrationCSS Sticky Parallax SectionsMulti-Scene Parallax Scrolling
View the full collection →