10 CSS Parallax Effects 01 / 10
CSS Parallax Hero Section
A luxury editorial hero built on five parallax layers — gradient bg, perspective grid, amber orbs, diagonal geometry SVG, and floating headline — each drifting at its own cadence.
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-01">
<!-- HERO -->
<section class="plx-01__hero">
<div class="plx-01__bg-layer" data-parallax="0.5"></div>
<div class="plx-01__grain"></div>
<div class="plx-01__orb plx-01__orb--a" data-parallax="0.3"></div>
<div class="plx-01__orb plx-01__orb--b" data-parallax="0.4"></div>
<div class="plx-01__lines" data-parallax="0.25">
<svg viewBox="0 0 1440 900" preserveAspectRatio="xMidYMid slice">
<line x1="0" y1="200" x2="1440" y2="700" stroke="#c8a95a" stroke-width="1"/>
<line x1="0" y1="400" x2="1440" y2="900" stroke="#c8a95a" stroke-width="0.5"/>
<line x1="200" y1="0" x2="800" y2="900" stroke="#c8a95a" stroke-width="0.5"/>
<line x1="900" y1="0" x2="1440" y2="600" stroke="#c8a95a" stroke-width="1"/>
<circle cx="720" cy="450" r="280" stroke="#c8a95a" stroke-width="0.5" fill="none"/>
<circle cx="720" cy="450" r="180" stroke="#c8a95a" stroke-width="0.3" fill="none"/>
</svg>
</div>
<div class="plx-01__content">
<div class="plx-01__eyebrow">Est. 2024 · Design Studio</div>
<h1 class="plx-01__headline" data-parallax="-0.15">
WHERE<br>FORM<br><em>MEETS</em><br>FUNCTION
</h1>
<p class="plx-01__sub" data-parallax="-0.08">
Crafting digital experiences that leave a lasting impression.
We build at the intersection of art, technology, and human desire.
</p>
<div class="plx-01__cta">
<button class="plx-01__btn plx-01__btn--primary">View Our Work</button>
<button class="plx-01__btn plx-01__btn--secondary">Get in Touch</button>
</div>
</div>
<div class="plx-01__scroll">
<span>Scroll</span>
<div class="plx-01__scroll-line"></div>
</div>
</section>
<!-- SECTION -->
<section class="plx-01__section">
<div class="plx-01__section-img">
<div class="plx-01__section-inner" data-parallax-section="0.3"></div>
</div>
<div class="plx-01__section-text">
<h2>Precision in <span>Every</span> Pixel</h2>
<div class="plx-01__rule"></div>
<p>We approach design as a discipline of reduction — stripping away everything that isn't essential until only the pure signal remains.</p>
<p>Every interaction is intentional. Every animation has a reason. Every color earns its place.</p>
<div class="plx-01__stat-row">
<div class="plx-01__stat"><strong>120+</strong><small>Projects</small></div>
<div class="plx-01__stat"><strong>8yr</strong><small>Experience</small></div>
<div class="plx-01__stat"><strong>14</strong><small>Awards</small></div>
</div>
</div>
</section>
<!-- BAND -->
<div class="plx-01__band">
<div class="plx-01__band-inner" data-parallax-band="0.4"></div>
<div class="plx-01__marquee">
DESIGN · DEVELOP · DELIVER · DESIGN · DEVELOP · DELIVER ·
DESIGN · DEVELOP · DELIVER · DESIGN · DEVELOP · DELIVER ·
</div>
<div class="plx-01__band-text">We Build What Others Only Imagine</div>
</div>
</div> <div class="plx-01">
<!-- HERO -->
<section class="plx-01__hero">
<div class="plx-01__bg-layer" data-parallax="0.5"></div>
<div class="plx-01__grain"></div>
<div class="plx-01__orb plx-01__orb--a" data-parallax="0.3"></div>
<div class="plx-01__orb plx-01__orb--b" data-parallax="0.4"></div>
<div class="plx-01__lines" data-parallax="0.25">
<svg viewBox="0 0 1440 900" preserveAspectRatio="xMidYMid slice">
<line x1="0" y1="200" x2="1440" y2="700" stroke="#c8a95a" stroke-width="1"/>
<line x1="0" y1="400" x2="1440" y2="900" stroke="#c8a95a" stroke-width="0.5"/>
<line x1="200" y1="0" x2="800" y2="900" stroke="#c8a95a" stroke-width="0.5"/>
<line x1="900" y1="0" x2="1440" y2="600" stroke="#c8a95a" stroke-width="1"/>
<circle cx="720" cy="450" r="280" stroke="#c8a95a" stroke-width="0.5" fill="none"/>
<circle cx="720" cy="450" r="180" stroke="#c8a95a" stroke-width="0.3" fill="none"/>
</svg>
</div>
<div class="plx-01__content">
<div class="plx-01__eyebrow">Est. 2024 · Design Studio</div>
<h1 class="plx-01__headline" data-parallax="-0.15">
WHERE<br>FORM<br><em>MEETS</em><br>FUNCTION
</h1>
<p class="plx-01__sub" data-parallax="-0.08">
Crafting digital experiences that leave a lasting impression.
We build at the intersection of art, technology, and human desire.
</p>
<div class="plx-01__cta">
<button class="plx-01__btn plx-01__btn--primary">View Our Work</button>
<button class="plx-01__btn plx-01__btn--secondary">Get in Touch</button>
</div>
</div>
<div class="plx-01__scroll">
<span>Scroll</span>
<div class="plx-01__scroll-line"></div>
</div>
</section>
<!-- SECTION -->
<section class="plx-01__section">
<div class="plx-01__section-img">
<div class="plx-01__section-inner" data-parallax-section="0.3"></div>
</div>
<div class="plx-01__section-text">
<h2>Precision in <span>Every</span> Pixel</h2>
<div class="plx-01__rule"></div>
<p>We approach design as a discipline of reduction — stripping away everything that isn't essential until only the pure signal remains.</p>
<p>Every interaction is intentional. Every animation has a reason. Every color earns its place.</p>
<div class="plx-01__stat-row">
<div class="plx-01__stat"><strong>120+</strong><small>Projects</small></div>
<div class="plx-01__stat"><strong>8yr</strong><small>Experience</small></div>
<div class="plx-01__stat"><strong>14</strong><small>Awards</small></div>
</div>
</div>
</section>
<!-- BAND -->
<div class="plx-01__band">
<div class="plx-01__band-inner" data-parallax-band="0.4"></div>
<div class="plx-01__marquee">
DESIGN · DEVELOP · DELIVER · DESIGN · DEVELOP · DELIVER ·
DESIGN · DEVELOP · DELIVER · DESIGN · DEVELOP · DELIVER ·
</div>
<div class="plx-01__band-text">We Build What Others Only Imagine</div>
</div>
</div>*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
.plx-01 {
--ink: #0a0a0f;
--cream: #f5f0e8;
--gold: #c8a95a;
--rust: #b84c2a;
font-family: 'Inter', sans-serif;
background: var(--ink);
color: var(--cream);
overflow-x: hidden;
}
/* ── Hero ── */
.plx-01__hero {
position: relative;
height: 100vh;
min-height: 600px;
overflow: hidden;
display: flex;
/* align-items: safe center — center the content when there's
enough room, but fall back to flex-start when content would
overflow. Without the safe keyword, flex centers content
even when it overflows the container, which COMBINED with
overflow:hidden above causes the top + bottom of the
content to be clipped equally (the user reported "top and
bottom of the view cut"). The safe keyword is the modern
fix — Chrome 93+, Safari 16+, Firefox 63+. justify-content
stays plain center since horizontal alignment never overflows
in this layout. */
align-items: safe center;
justify-content: center;
padding: 24px 0;
}
.plx-01__bg-layer {
position: absolute;
inset: -30%;
background:
radial-gradient(ellipse 80% 60% at 60% 40%, rgba(200,169,90,0.18) 0%, transparent 60%),
radial-gradient(ellipse 40% 40% at 20% 70%, rgba(184,76,42,0.22) 0%, transparent 55%),
linear-gradient(160deg, #0d0b18 0%, #1a0f0a 50%, #0a0d1a 100%);
will-change: transform;
transform: translateY(0px);
}
/* Grain texture overlay */
.plx-01__grain {
position: absolute;
inset: 0;
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.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
background-size: 200px 200px;
opacity: 0.5;
pointer-events: none;
}
/* Geometric lines */
.plx-01__lines {
position: absolute;
inset: 0;
will-change: transform;
transform: translateY(0px);
}
.plx-01__lines svg {
width: 100%; height: 100%;
opacity: 0.12;
}
/* Floating orbs */
.plx-01__orb {
position: absolute;
border-radius: 50%;
filter: blur(60px);
will-change: transform;
transform: translateY(0px);
}
.plx-01__orb--a {
width: 420px; height: 420px;
background: radial-gradient(circle, rgba(200,169,90,0.4) 0%, transparent 70%);
top: -10%; right: -5%;
}
.plx-01__orb--b {
width: 300px; height: 300px;
background: radial-gradient(circle, rgba(184,76,42,0.35) 0%, transparent 70%);
bottom: -5%; left: 5%;
}
/* Content — scrolls at normal speed */
.plx-01__content {
position: relative;
z-index: 10;
text-align: center;
padding: 0 24px;
max-width: 900px;
}
.plx-01__eyebrow {
display: inline-block;
font-size: 11px;
letter-spacing: 0.35em;
text-transform: uppercase;
color: var(--gold);
border: 1px solid rgba(200,169,90,0.4);
padding: 6px 18px;
margin-bottom: 36px;
border-radius: 2px;
}
.plx-01__headline {
font-family: 'Bebas Neue', sans-serif;
/* Sizing math (derived empirically, measured in browser):
The headline has 4 forced <br> stacked lines + line-height 0.88,
so its block height = font_size × 0.88 × 4 = font_size × 3.52.
Other content + margins in the hero (eyebrow + sub + cta +
padding + scroll-indicator clearance) measured to ~360px.
For everything to fit in 100vh without clipping, headline block
needs to be ≤ (100vh - 360px), so font_size ≤ (100vh - 360px) / 3.52.
This calc-driven ceiling means the headline scales naturally
with available viewport height: ~205px at desktop 1080px viewport
(clamps to 180px ceiling from the design intent), ~83px in the
playground iframe at 651px height (vs the previous 97px that
overflowed the bottom CTAs), 56px floor on short mobile.
14vw secondary constraint stops the headline being too wide on
very wide-but-short viewports. Floor 56px handles 360px-wide
phones. Ceiling 180px = 13rem from the demo desc. */
font-size: clamp(56px, min(14vw, calc((100vh - 380px) / 3.52)), 180px);
line-height: 0.88;
letter-spacing: -0.01em;
color: var(--cream);
will-change: transform;
transform: translateY(0px);
}
.plx-01__headline em {
font-style: normal;
display: block;
background: linear-gradient(135deg, var(--gold) 0%, var(--rust) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.plx-01__sub {
margin-top: 32px;
font-size: 16px;
font-weight: 300;
line-height: 1.7;
color: rgba(245,240,232,0.6);
max-width: 500px;
margin-left: auto;
margin-right: auto;
will-change: transform;
transform: translateY(0px);
}
.plx-01__cta {
margin-top: 48px;
display: inline-flex;
gap: 16px;
flex-wrap: wrap;
justify-content: center;
}
.plx-01__btn {
padding: 14px 36px;
font-size: 13px;
letter-spacing: 0.15em;
text-transform: uppercase;
border: none;
cursor: pointer;
font-family: 'Inter', sans-serif;
font-weight: 600;
transition: transform 0.2s, box-shadow 0.2s;
}
.plx-01__btn--primary {
background: linear-gradient(135deg, var(--gold), var(--rust));
color: var(--ink);
}
.plx-01__btn--secondary {
background: transparent;
color: var(--cream);
border: 1px solid rgba(245,240,232,0.3);
}
.plx-01__btn:hover { transform: translateY(-2px); box-shadow: 0 12px 40px rgba(200,169,90,0.25); }
/* Scroll indicator — original design: absolute-positioned at
the hero's bottom-center, sits at the bottom edge of the
100vh hero regardless of content height. Visible whenever
content doesn't extend into the bottom 80px (which the new
headline clamp prevents thanks to the 22vh component). */
.plx-01__scroll {
position: absolute;
bottom: 40px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
opacity: 0.5;
z-index: 10;
pointer-events: none;
}
.plx-01__scroll span {
font-size: 10px;
letter-spacing: 0.2em;
text-transform: uppercase;
}
.plx-01__scroll-line {
width: 1px;
height: 48px;
background: linear-gradient(to bottom, var(--gold), transparent);
animation: plx-01-scroll-pulse 2s ease-in-out infinite;
}
@keyframes plx-01-scroll-pulse {
0%, 100% { opacity: 0.3; transform: scaleY(1); }
50% { opacity: 1; transform: scaleY(0.6); }
}
/* ── Content sections below hero ── */
.plx-01__section {
position: relative;
padding: 120px 40px;
max-width: 1100px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 80px;
align-items: center;
}
.plx-01__section-img {
position: relative;
aspect-ratio: 4/5;
overflow: hidden;
border: 1px solid rgba(200,169,90,0.2);
}
.plx-01__section-inner {
position: absolute;
inset: -20%;
background:
linear-gradient(135deg, #1a120a 0%, #0f1520 100%);
will-change: transform;
}
.plx-01__section-inner::after {
content: '';
position: absolute;
inset: 20%;
background: radial-gradient(circle at 40% 60%, rgba(200,169,90,0.3) 0%, rgba(184,76,42,0.2) 40%, transparent 70%);
border: 1px solid rgba(200,169,90,0.15);
}
.plx-01__section-text h2 {
font-family: 'Bebas Neue', sans-serif;
font-size: clamp(42px, 6vw, 72px);
line-height: 0.95;
margin-bottom: 24px;
}
.plx-01__section-text h2 span {
color: var(--gold);
}
.plx-01__section-text p {
font-size: 15px;
line-height: 1.75;
color: rgba(245,240,232,0.6);
margin-bottom: 16px;
}
.plx-01__rule {
width: 48px;
height: 2px;
background: linear-gradient(90deg, var(--gold), transparent);
margin: 32px 0;
}
.plx-01__stat-row {
display: flex;
gap: 40px;
margin-top: 40px;
}
.plx-01__stat strong {
display: block;
font-family: 'Bebas Neue', sans-serif;
font-size: 42px;
color: var(--gold);
line-height: 1;
}
.plx-01__stat small {
font-size: 11px;
letter-spacing: 0.15em;
text-transform: uppercase;
color: rgba(245,240,232,0.4);
}
/* Divider band */
.plx-01__band {
background: linear-gradient(135deg, var(--gold) 0%, var(--rust) 100%);
padding: 40px;
text-align: center;
overflow: hidden;
position: relative;
}
.plx-01__band-inner {
position: absolute;
inset: -20%;
will-change: transform;
}
.plx-01__marquee {
font-family: 'Bebas Neue', sans-serif;
font-size: 64px;
color: rgba(10,10,15,0.12);
white-space: nowrap;
position: relative;
z-index: 1;
animation: plx-01-marquee 18s linear infinite;
}
@keyframes plx-01-marquee {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
.plx-01__band-text {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
letter-spacing: 0.25em;
text-transform: uppercase;
color: var(--ink);
font-weight: 600;
}
@media (max-width: 768px) {
.plx-01__section {
grid-template-columns: 1fr;
gap: 40px;
padding: 80px 24px;
}
.plx-01__section-img { display: none; }
}
@media (prefers-reduced-motion: reduce) {
.plx-01__bg-layer,
.plx-01__lines,
.plx-01__orb,
.plx-01__headline,
.plx-01__sub,
.plx-01__section-inner { transform: none !important; }
.plx-01__scroll-line { animation: none; }
.plx-01__marquee { animation: none; }
} *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
.plx-01 {
--ink: #0a0a0f;
--cream: #f5f0e8;
--gold: #c8a95a;
--rust: #b84c2a;
font-family: 'Inter', sans-serif;
background: var(--ink);
color: var(--cream);
overflow-x: hidden;
}
/* ── Hero ── */
.plx-01__hero {
position: relative;
height: 100vh;
min-height: 600px;
overflow: hidden;
display: flex;
/* align-items: safe center — center the content when there's
enough room, but fall back to flex-start when content would
overflow. Without the safe keyword, flex centers content
even when it overflows the container, which COMBINED with
overflow:hidden above causes the top + bottom of the
content to be clipped equally (the user reported "top and
bottom of the view cut"). The safe keyword is the modern
fix — Chrome 93+, Safari 16+, Firefox 63+. justify-content
stays plain center since horizontal alignment never overflows
in this layout. */
align-items: safe center;
justify-content: center;
padding: 24px 0;
}
.plx-01__bg-layer {
position: absolute;
inset: -30%;
background:
radial-gradient(ellipse 80% 60% at 60% 40%, rgba(200,169,90,0.18) 0%, transparent 60%),
radial-gradient(ellipse 40% 40% at 20% 70%, rgba(184,76,42,0.22) 0%, transparent 55%),
linear-gradient(160deg, #0d0b18 0%, #1a0f0a 50%, #0a0d1a 100%);
will-change: transform;
transform: translateY(0px);
}
/* Grain texture overlay */
.plx-01__grain {
position: absolute;
inset: 0;
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.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
background-size: 200px 200px;
opacity: 0.5;
pointer-events: none;
}
/* Geometric lines */
.plx-01__lines {
position: absolute;
inset: 0;
will-change: transform;
transform: translateY(0px);
}
.plx-01__lines svg {
width: 100%; height: 100%;
opacity: 0.12;
}
/* Floating orbs */
.plx-01__orb {
position: absolute;
border-radius: 50%;
filter: blur(60px);
will-change: transform;
transform: translateY(0px);
}
.plx-01__orb--a {
width: 420px; height: 420px;
background: radial-gradient(circle, rgba(200,169,90,0.4) 0%, transparent 70%);
top: -10%; right: -5%;
}
.plx-01__orb--b {
width: 300px; height: 300px;
background: radial-gradient(circle, rgba(184,76,42,0.35) 0%, transparent 70%);
bottom: -5%; left: 5%;
}
/* Content — scrolls at normal speed */
.plx-01__content {
position: relative;
z-index: 10;
text-align: center;
padding: 0 24px;
max-width: 900px;
}
.plx-01__eyebrow {
display: inline-block;
font-size: 11px;
letter-spacing: 0.35em;
text-transform: uppercase;
color: var(--gold);
border: 1px solid rgba(200,169,90,0.4);
padding: 6px 18px;
margin-bottom: 36px;
border-radius: 2px;
}
.plx-01__headline {
font-family: 'Bebas Neue', sans-serif;
/* Sizing math (derived empirically, measured in browser):
The headline has 4 forced <br> stacked lines + line-height 0.88,
so its block height = font_size × 0.88 × 4 = font_size × 3.52.
Other content + margins in the hero (eyebrow + sub + cta +
padding + scroll-indicator clearance) measured to ~360px.
For everything to fit in 100vh without clipping, headline block
needs to be ≤ (100vh - 360px), so font_size ≤ (100vh - 360px) / 3.52.
This calc-driven ceiling means the headline scales naturally
with available viewport height: ~205px at desktop 1080px viewport
(clamps to 180px ceiling from the design intent), ~83px in the
playground iframe at 651px height (vs the previous 97px that
overflowed the bottom CTAs), 56px floor on short mobile.
14vw secondary constraint stops the headline being too wide on
very wide-but-short viewports. Floor 56px handles 360px-wide
phones. Ceiling 180px = 13rem from the demo desc. */
font-size: clamp(56px, min(14vw, calc((100vh - 380px) / 3.52)), 180px);
line-height: 0.88;
letter-spacing: -0.01em;
color: var(--cream);
will-change: transform;
transform: translateY(0px);
}
.plx-01__headline em {
font-style: normal;
display: block;
background: linear-gradient(135deg, var(--gold) 0%, var(--rust) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.plx-01__sub {
margin-top: 32px;
font-size: 16px;
font-weight: 300;
line-height: 1.7;
color: rgba(245,240,232,0.6);
max-width: 500px;
margin-left: auto;
margin-right: auto;
will-change: transform;
transform: translateY(0px);
}
.plx-01__cta {
margin-top: 48px;
display: inline-flex;
gap: 16px;
flex-wrap: wrap;
justify-content: center;
}
.plx-01__btn {
padding: 14px 36px;
font-size: 13px;
letter-spacing: 0.15em;
text-transform: uppercase;
border: none;
cursor: pointer;
font-family: 'Inter', sans-serif;
font-weight: 600;
transition: transform 0.2s, box-shadow 0.2s;
}
.plx-01__btn--primary {
background: linear-gradient(135deg, var(--gold), var(--rust));
color: var(--ink);
}
.plx-01__btn--secondary {
background: transparent;
color: var(--cream);
border: 1px solid rgba(245,240,232,0.3);
}
.plx-01__btn:hover { transform: translateY(-2px); box-shadow: 0 12px 40px rgba(200,169,90,0.25); }
/* Scroll indicator — original design: absolute-positioned at
the hero's bottom-center, sits at the bottom edge of the
100vh hero regardless of content height. Visible whenever
content doesn't extend into the bottom 80px (which the new
headline clamp prevents thanks to the 22vh component). */
.plx-01__scroll {
position: absolute;
bottom: 40px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
opacity: 0.5;
z-index: 10;
pointer-events: none;
}
.plx-01__scroll span {
font-size: 10px;
letter-spacing: 0.2em;
text-transform: uppercase;
}
.plx-01__scroll-line {
width: 1px;
height: 48px;
background: linear-gradient(to bottom, var(--gold), transparent);
animation: plx-01-scroll-pulse 2s ease-in-out infinite;
}
@keyframes plx-01-scroll-pulse {
0%, 100% { opacity: 0.3; transform: scaleY(1); }
50% { opacity: 1; transform: scaleY(0.6); }
}
/* ── Content sections below hero ── */
.plx-01__section {
position: relative;
padding: 120px 40px;
max-width: 1100px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 80px;
align-items: center;
}
.plx-01__section-img {
position: relative;
aspect-ratio: 4/5;
overflow: hidden;
border: 1px solid rgba(200,169,90,0.2);
}
.plx-01__section-inner {
position: absolute;
inset: -20%;
background:
linear-gradient(135deg, #1a120a 0%, #0f1520 100%);
will-change: transform;
}
.plx-01__section-inner::after {
content: '';
position: absolute;
inset: 20%;
background: radial-gradient(circle at 40% 60%, rgba(200,169,90,0.3) 0%, rgba(184,76,42,0.2) 40%, transparent 70%);
border: 1px solid rgba(200,169,90,0.15);
}
.plx-01__section-text h2 {
font-family: 'Bebas Neue', sans-serif;
font-size: clamp(42px, 6vw, 72px);
line-height: 0.95;
margin-bottom: 24px;
}
.plx-01__section-text h2 span {
color: var(--gold);
}
.plx-01__section-text p {
font-size: 15px;
line-height: 1.75;
color: rgba(245,240,232,0.6);
margin-bottom: 16px;
}
.plx-01__rule {
width: 48px;
height: 2px;
background: linear-gradient(90deg, var(--gold), transparent);
margin: 32px 0;
}
.plx-01__stat-row {
display: flex;
gap: 40px;
margin-top: 40px;
}
.plx-01__stat strong {
display: block;
font-family: 'Bebas Neue', sans-serif;
font-size: 42px;
color: var(--gold);
line-height: 1;
}
.plx-01__stat small {
font-size: 11px;
letter-spacing: 0.15em;
text-transform: uppercase;
color: rgba(245,240,232,0.4);
}
/* Divider band */
.plx-01__band {
background: linear-gradient(135deg, var(--gold) 0%, var(--rust) 100%);
padding: 40px;
text-align: center;
overflow: hidden;
position: relative;
}
.plx-01__band-inner {
position: absolute;
inset: -20%;
will-change: transform;
}
.plx-01__marquee {
font-family: 'Bebas Neue', sans-serif;
font-size: 64px;
color: rgba(10,10,15,0.12);
white-space: nowrap;
position: relative;
z-index: 1;
animation: plx-01-marquee 18s linear infinite;
}
@keyframes plx-01-marquee {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
.plx-01__band-text {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
letter-spacing: 0.25em;
text-transform: uppercase;
color: var(--ink);
font-weight: 600;
}
@media (max-width: 768px) {
.plx-01__section {
grid-template-columns: 1fr;
gap: 40px;
padding: 80px 24px;
}
.plx-01__section-img { display: none; }
}
@media (prefers-reduced-motion: reduce) {
.plx-01__bg-layer,
.plx-01__lines,
.plx-01__orb,
.plx-01__headline,
.plx-01__sub,
.plx-01__section-inner { transform: none !important; }
.plx-01__scroll-line { animation: none; }
.plx-01__marquee { animation: none; }
}(() => {
const root = document.querySelector('.plx-01');
if (!root) return;
const hero = root.querySelector('.plx-01__hero');
const heroH = hero.offsetHeight;
// Elements with data-parallax on the hero
const heroLayers = Array.from(root.querySelectorAll('[data-parallax]')).map(el => ({
el,
speed: parseFloat(el.dataset.parallax)
}));
// Section inner parallax
const sectionInner = root.querySelector('[data-parallax-section]');
const sectionSpeed = sectionInner ? parseFloat(sectionInner.dataset.parallaxSection) : 0.3;
// Band inner parallax
const bandInner = root.querySelector('[data-parallax-band]');
const bandSpeed = bandInner ? parseFloat(bandInner.dataset.parallaxBand) : 0.4;
let ticking = false;
function onScroll() {
if (ticking) return;
ticking = true;
requestAnimationFrame(() => {
const sy = window.scrollY;
// Hero layers
heroLayers.forEach(({ el, speed }) => {
el.style.transform = `translateY(${sy * speed}px)`;
});
// Section inner — relative to its position
if (sectionInner) {
const rect = sectionInner.closest('.plx-01__section-img').getBoundingClientRect();
const relY = rect.top + rect.height / 2;
const offset = (relY - window.innerHeight / 2) * sectionSpeed;
sectionInner.style.transform = `translateY(${-offset * 0.4}px)`;
}
// Band inner
if (bandInner) {
const rect = bandInner.closest('.plx-01__band').getBoundingClientRect();
const relY = rect.top + rect.height / 2;
const offset = (relY - window.innerHeight / 2) * bandSpeed;
bandInner.style.transform = `translateX(${-offset * 0.2}px)`;
}
ticking = false;
});
}
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
})(); (() => {
const root = document.querySelector('.plx-01');
if (!root) return;
const hero = root.querySelector('.plx-01__hero');
const heroH = hero.offsetHeight;
// Elements with data-parallax on the hero
const heroLayers = Array.from(root.querySelectorAll('[data-parallax]')).map(el => ({
el,
speed: parseFloat(el.dataset.parallax)
}));
// Section inner parallax
const sectionInner = root.querySelector('[data-parallax-section]');
const sectionSpeed = sectionInner ? parseFloat(sectionInner.dataset.parallaxSection) : 0.3;
// Band inner parallax
const bandInner = root.querySelector('[data-parallax-band]');
const bandSpeed = bandInner ? parseFloat(bandInner.dataset.parallaxBand) : 0.4;
let ticking = false;
function onScroll() {
if (ticking) return;
ticking = true;
requestAnimationFrame(() => {
const sy = window.scrollY;
// Hero layers
heroLayers.forEach(({ el, speed }) => {
el.style.transform = `translateY(${sy * speed}px)`;
});
// Section inner — relative to its position
if (sectionInner) {
const rect = sectionInner.closest('.plx-01__section-img').getBoundingClientRect();
const relY = rect.top + rect.height / 2;
const offset = (relY - window.innerHeight / 2) * sectionSpeed;
sectionInner.style.transform = `translateY(${-offset * 0.4}px)`;
}
// Band inner
if (bandInner) {
const rect = bandInner.closest('.plx-01__band').getBoundingClientRect();
const relY = rect.top + rect.height / 2;
const offset = (relY - window.innerHeight / 2) * bandSpeed;
bandInner.style.transform = `translateX(${-offset * 0.2}px)`;
}
ticking = false;
});
}
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
})();More from 10 CSS Parallax Effects
Multi-layered CSS Parallax Landscape / IllustrationCSS Sticky Parallax SectionsMulti-Scene Parallax ScrollingCSS Parallax Image Grid / GalleryCSS Horizontal Parallax ScrollCSS Parallax Text Overlay EffectCSS Parallax Card Hover EffectCSS Zoom-In / Depth Parallax on ScrollCSS Parallax Background Blur Transition
View the full collection →