10 CSS Parallax Effects 07 / 10
CSS Parallax Text Overlay Effect
Three typographic scenes demonstrating the fixed-text / sliding-texture trick.
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-07">
<!-- SCENE 1: Display headline / scrolling stripe bg -->
<section class="plx-07__s1">
<div class="plx-07__s1-pin">
<div class="plx-07__s1-bg" id="plx07-s1-bg"></div>
<div class="plx-07__s1-text">
<span class="plx-07__display" id="plx07-line1">TYPE</span>
<span class="plx-07__display is-outline" id="plx07-line2">OVER</span>
<span class="plx-07__display is-accent" id="plx07-line3">IMAGE</span>
</div>
<p class="plx-07__s1-label">Background scrolls · Text stays</p>
</div>
</section>
<!-- SCENE 2: Quote / bg moves faster than text -->
<section class="plx-07__s2">
<div class="plx-07__s2-pin">
<div class="plx-07__s2-bg" id="plx07-s2-bg"></div>
<div class="plx-07__quote-wrap" id="plx07-quote">
<span class="plx-07__qmark">"</span>
<p class="plx-07__qtext">
Design is the art of making decisions <em>invisible.</em>
The best interface is the one you never notice —
only the <em>experience</em> remains.
<span class="plx-07__qattr">— A Designer Who Believed It</span>
</p>
</div>
</div>
</section>
<!-- SCENE 3: Split word / bg slides under it -->
<section class="plx-07__s3">
<div class="plx-07__s3-pin">
<div class="plx-07__s3-bg" id="plx07-s3-bg"></div>
<div class="plx-07__word-wrap" id="plx07-word">
<span class="plx-07__word-solid">BOLD</span>
<span class="plx-07__word-outline">BOLD</span>
</div>
<div class="plx-07__s3-caption">
<h3>The texture moves;<br>the word doesn't.</h3>
<p>Massive display type stays anchored while the rich background texture shifts beneath it. The contrast between stillness and motion creates instant depth.</p>
</div>
</div>
</section>
<div class="plx-07__footer">
<h2>Words that <em>command</em> space.</h2>
<p>The parallax text overlay technique uses motion differential between typography and background to create perceived depth on a flat screen.</p>
</div>
</div> <div class="plx-07">
<!-- SCENE 1: Display headline / scrolling stripe bg -->
<section class="plx-07__s1">
<div class="plx-07__s1-pin">
<div class="plx-07__s1-bg" id="plx07-s1-bg"></div>
<div class="plx-07__s1-text">
<span class="plx-07__display" id="plx07-line1">TYPE</span>
<span class="plx-07__display is-outline" id="plx07-line2">OVER</span>
<span class="plx-07__display is-accent" id="plx07-line3">IMAGE</span>
</div>
<p class="plx-07__s1-label">Background scrolls · Text stays</p>
</div>
</section>
<!-- SCENE 2: Quote / bg moves faster than text -->
<section class="plx-07__s2">
<div class="plx-07__s2-pin">
<div class="plx-07__s2-bg" id="plx07-s2-bg"></div>
<div class="plx-07__quote-wrap" id="plx07-quote">
<span class="plx-07__qmark">"</span>
<p class="plx-07__qtext">
Design is the art of making decisions <em>invisible.</em>
The best interface is the one you never notice —
only the <em>experience</em> remains.
<span class="plx-07__qattr">— A Designer Who Believed It</span>
</p>
</div>
</div>
</section>
<!-- SCENE 3: Split word / bg slides under it -->
<section class="plx-07__s3">
<div class="plx-07__s3-pin">
<div class="plx-07__s3-bg" id="plx07-s3-bg"></div>
<div class="plx-07__word-wrap" id="plx07-word">
<span class="plx-07__word-solid">BOLD</span>
<span class="plx-07__word-outline">BOLD</span>
</div>
<div class="plx-07__s3-caption">
<h3>The texture moves;<br>the word doesn't.</h3>
<p>Massive display type stays anchored while the rich background texture shifts beneath it. The contrast between stillness and motion creates instant depth.</p>
</div>
</div>
</section>
<div class="plx-07__footer">
<h2>Words that <em>command</em> space.</h2>
<p>The parallax text overlay technique uses motion differential between typography and background to create perceived depth on a flat screen.</p>
</div>
</div>.plx-07, .plx-07 *, .plx-07 *::before, .plx-07 *::after {
box-sizing: border-box; margin: 0; padding: 0;
}
.plx-07 {
font-family: 'DM Sans', sans-serif;
background: #0c0c0a;
color: #f4f0e8;
/* overflow:clip not overflow:hidden — see Demo 09 + 10 fixes.
overflow:hidden creates a scroll context that breaks
position:sticky on descendants. */
overflow-x: clip;
}
/* ═══ SCENE 1: Headline stays fixed, stripe bg scrolls beneath ═══ */
.plx-07__s1 {
position: relative;
/* 300vh = 200vh of sticky pin runway during which the JS
animates bg + text overlays. Sticky pinning works because
.plx-07 root uses overflow-x:clip (not :hidden) — the
:hidden form would create a scroll context that breaks
sticky on descendants. */
height: 300vh;
}
.plx-07__s1-pin {
position: sticky;
top: 0;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
/* Diagonal stripe background — this is what scrolls */
.plx-07__s1-bg {
position: absolute;
inset: -30%;
will-change: transform;
background:
repeating-linear-gradient(
-55deg,
rgba(220,160,60,0.0) 0px,
rgba(220,160,60,0.0) 30px,
rgba(220,160,60,0.06) 30px,
rgba(220,160,60,0.06) 32px,
rgba(220,160,60,0.0) 32px,
rgba(220,160,60,0.0) 62px,
rgba(220,160,60,0.1) 62px,
rgba(220,160,60,0.1) 64px
),
radial-gradient(ellipse at 30% 50%, rgba(180,100,20,0.25) 0%, transparent 55%),
radial-gradient(ellipse at 75% 30%, rgba(100,60,140,0.2) 0%, transparent 50%),
linear-gradient(160deg, #1a1206 0%, #0c0c0a 60%, #060810 100%);
}
/* The text itself — stays put */
.plx-07__s1-text {
position: relative;
z-index: 5;
text-align: center;
mix-blend-mode: normal;
}
.plx-07__display {
display: block;
font-family: 'Anton', sans-serif;
font-size: clamp(72px, 16vw, 210px);
line-height: 0.88;
letter-spacing: -0.02em;
color: #f4f0e8;
text-transform: uppercase;
will-change: transform;
}
.plx-07__display.is-outline {
color: transparent;
-webkit-text-stroke: 2px rgba(244,240,232,0.25);
}
.plx-07__display.is-accent {
color: #dca03c;
}
/* S1 progress-driven: bg scrolls while text moves subtly in opposite dir */
/* S1 label */
.plx-07__s1-label {
position: absolute;
bottom: 40px;
left: 50%;
transform: translateX(-50%);
font-size: 9px;
font-family: 'DM Sans', sans-serif;
letter-spacing: 0.3em;
text-transform: uppercase;
opacity: 0.3;
white-space: nowrap;
}
/* ═══ SCENE 2: Quote — text and bg move at different rates ═══ */
.plx-07__s2 {
position: relative;
/* See plx-07__s1 comment above for rationale. */
height: 300vh;
background: #0a0e12;
}
.plx-07__s2-pin {
position: sticky;
top: 0;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
}
.plx-07__s2-bg {
position: absolute;
inset: -30%;
will-change: transform;
background:
repeating-linear-gradient(
25deg,
rgba(100,160,220,0.0) 0px,
rgba(100,160,220,0.0) 50px,
rgba(100,160,220,0.05) 50px,
rgba(100,160,220,0.05) 52px
),
radial-gradient(ellipse at 70% 60%, rgba(60,100,180,0.3) 0%, transparent 55%),
radial-gradient(ellipse at 20% 30%, rgba(180,60,120,0.2) 0%, transparent 50%),
linear-gradient(160deg, #060810 0%, #0a0e14 100%);
}
.plx-07__quote-wrap {
position: relative;
z-index: 5;
padding: 0 clamp(40px, 10vw, 140px);
will-change: transform;
max-width: 1100px;
}
.plx-07__qmark {
display: block;
font-family: 'Lora', serif;
font-size: clamp(120px, 20vw, 220px);
line-height: 0.7;
color: rgba(100,160,220,0.2);
margin-bottom: -24px;
}
.plx-07__qtext {
font-family: 'Lora', serif;
font-style: italic;
font-size: clamp(24px, 4.5vw, 58px);
line-height: 1.35;
font-weight: 400;
color: #f4f0e8;
}
.plx-07__qtext em {
font-style: normal;
color: #7eb8e0;
}
.plx-07__qattr {
display: block;
margin-top: 32px;
font-size: 10px;
letter-spacing: 0.3em;
text-transform: uppercase;
opacity: 0.35;
font-style: normal;
font-family: 'DM Sans', sans-serif;
}
/* ═══ SCENE 3: Giant word — top half normal, bottom half outline, bg scrolls ═══ */
.plx-07__s3 {
position: relative;
/* See plx-07__s1 comment above for rationale. */
height: 300vh;
background: #100c08;
}
.plx-07__s3-pin {
position: sticky;
top: 0;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: flex-end;
}
.plx-07__s3-bg {
position: absolute;
inset: -30%;
will-change: transform;
background:
repeating-linear-gradient(
0deg,
rgba(220,140,60,0.0) 0px,
rgba(220,140,60,0.0) 20px,
rgba(220,140,60,0.05) 20px,
rgba(220,140,60,0.05) 21px
),
radial-gradient(ellipse at 60% 45%, rgba(200,100,20,0.3) 0%, transparent 55%),
linear-gradient(160deg, #100c06 0%, #180e04 100%);
}
/* Giant split word */
.plx-07__word-wrap {
position: relative;
z-index: 5;
padding-right: clamp(30px, 8vw, 120px);
will-change: transform;
line-height: 0.88;
}
.plx-07__word-solid {
display: block;
font-family: 'Anton', sans-serif;
font-size: clamp(90px, 20vw, 270px);
letter-spacing: -0.04em;
color: #f4f0e8;
/* clip to top 50% */
clip-path: inset(0 0 50% 0);
line-height: 0.88;
}
.plx-07__word-outline {
display: block;
font-family: 'Anton', sans-serif;
font-size: clamp(90px, 20vw, 270px);
letter-spacing: -0.04em;
color: transparent;
-webkit-text-stroke: 2px rgba(244,240,232,0.4);
/* offset up to align perfectly */
margin-top: calc(clamp(90px, 20vw, 270px) * -0.88);
clip-path: inset(50% 0 0 0);
line-height: 0.88;
}
/* Caption text left side */
.plx-07__s3-caption {
position: absolute;
left: clamp(30px, 6vw, 80px);
bottom: 60px;
z-index: 6;
max-width: 260px;
}
.plx-07__s3-caption h3 {
font-family: 'Lora', serif;
font-style: italic;
font-size: clamp(18px, 2.5vw, 26px);
font-weight: 400;
line-height: 1.4;
margin-bottom: 12px;
}
.plx-07__s3-caption p {
font-size: 13px;
font-weight: 300;
line-height: 1.8;
opacity: 0.45;
}
/* ═══ Footer ═══ */
.plx-07__footer {
background: #f4f0e8;
color: #0c0c0a;
padding: 100px 60px;
text-align: center;
}
.plx-07__footer h2 {
font-family: 'Anton', sans-serif;
font-size: clamp(32px, 6vw, 80px);
letter-spacing: -0.03em;
text-transform: uppercase;
margin-bottom: 20px;
}
.plx-07__footer h2 em {
font-family: 'Lora', serif;
font-style: italic;
font-weight: 400;
color: #b87020;
}
.plx-07__footer p {
font-size: 15px;
font-weight: 300;
line-height: 1.8;
opacity: 0.55;
max-width: 480px;
margin: 0 auto;
}
@media (max-width: 600px) {
.plx-07__s3-caption { display: none; }
}
@media (prefers-reduced-motion: reduce) {
.plx-07__s1-bg, .plx-07__s2-bg, .plx-07__s2-bg, .plx-07__s3-bg,
.plx-07__quote-wrap, .plx-07__word-wrap, .plx-07__display { transform: none !important; }
} .plx-07, .plx-07 *, .plx-07 *::before, .plx-07 *::after {
box-sizing: border-box; margin: 0; padding: 0;
}
.plx-07 {
font-family: 'DM Sans', sans-serif;
background: #0c0c0a;
color: #f4f0e8;
/* overflow:clip not overflow:hidden — see Demo 09 + 10 fixes.
overflow:hidden creates a scroll context that breaks
position:sticky on descendants. */
overflow-x: clip;
}
/* ═══ SCENE 1: Headline stays fixed, stripe bg scrolls beneath ═══ */
.plx-07__s1 {
position: relative;
/* 300vh = 200vh of sticky pin runway during which the JS
animates bg + text overlays. Sticky pinning works because
.plx-07 root uses overflow-x:clip (not :hidden) — the
:hidden form would create a scroll context that breaks
sticky on descendants. */
height: 300vh;
}
.plx-07__s1-pin {
position: sticky;
top: 0;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
/* Diagonal stripe background — this is what scrolls */
.plx-07__s1-bg {
position: absolute;
inset: -30%;
will-change: transform;
background:
repeating-linear-gradient(
-55deg,
rgba(220,160,60,0.0) 0px,
rgba(220,160,60,0.0) 30px,
rgba(220,160,60,0.06) 30px,
rgba(220,160,60,0.06) 32px,
rgba(220,160,60,0.0) 32px,
rgba(220,160,60,0.0) 62px,
rgba(220,160,60,0.1) 62px,
rgba(220,160,60,0.1) 64px
),
radial-gradient(ellipse at 30% 50%, rgba(180,100,20,0.25) 0%, transparent 55%),
radial-gradient(ellipse at 75% 30%, rgba(100,60,140,0.2) 0%, transparent 50%),
linear-gradient(160deg, #1a1206 0%, #0c0c0a 60%, #060810 100%);
}
/* The text itself — stays put */
.plx-07__s1-text {
position: relative;
z-index: 5;
text-align: center;
mix-blend-mode: normal;
}
.plx-07__display {
display: block;
font-family: 'Anton', sans-serif;
font-size: clamp(72px, 16vw, 210px);
line-height: 0.88;
letter-spacing: -0.02em;
color: #f4f0e8;
text-transform: uppercase;
will-change: transform;
}
.plx-07__display.is-outline {
color: transparent;
-webkit-text-stroke: 2px rgba(244,240,232,0.25);
}
.plx-07__display.is-accent {
color: #dca03c;
}
/* S1 progress-driven: bg scrolls while text moves subtly in opposite dir */
/* S1 label */
.plx-07__s1-label {
position: absolute;
bottom: 40px;
left: 50%;
transform: translateX(-50%);
font-size: 9px;
font-family: 'DM Sans', sans-serif;
letter-spacing: 0.3em;
text-transform: uppercase;
opacity: 0.3;
white-space: nowrap;
}
/* ═══ SCENE 2: Quote — text and bg move at different rates ═══ */
.plx-07__s2 {
position: relative;
/* See plx-07__s1 comment above for rationale. */
height: 300vh;
background: #0a0e12;
}
.plx-07__s2-pin {
position: sticky;
top: 0;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
}
.plx-07__s2-bg {
position: absolute;
inset: -30%;
will-change: transform;
background:
repeating-linear-gradient(
25deg,
rgba(100,160,220,0.0) 0px,
rgba(100,160,220,0.0) 50px,
rgba(100,160,220,0.05) 50px,
rgba(100,160,220,0.05) 52px
),
radial-gradient(ellipse at 70% 60%, rgba(60,100,180,0.3) 0%, transparent 55%),
radial-gradient(ellipse at 20% 30%, rgba(180,60,120,0.2) 0%, transparent 50%),
linear-gradient(160deg, #060810 0%, #0a0e14 100%);
}
.plx-07__quote-wrap {
position: relative;
z-index: 5;
padding: 0 clamp(40px, 10vw, 140px);
will-change: transform;
max-width: 1100px;
}
.plx-07__qmark {
display: block;
font-family: 'Lora', serif;
font-size: clamp(120px, 20vw, 220px);
line-height: 0.7;
color: rgba(100,160,220,0.2);
margin-bottom: -24px;
}
.plx-07__qtext {
font-family: 'Lora', serif;
font-style: italic;
font-size: clamp(24px, 4.5vw, 58px);
line-height: 1.35;
font-weight: 400;
color: #f4f0e8;
}
.plx-07__qtext em {
font-style: normal;
color: #7eb8e0;
}
.plx-07__qattr {
display: block;
margin-top: 32px;
font-size: 10px;
letter-spacing: 0.3em;
text-transform: uppercase;
opacity: 0.35;
font-style: normal;
font-family: 'DM Sans', sans-serif;
}
/* ═══ SCENE 3: Giant word — top half normal, bottom half outline, bg scrolls ═══ */
.plx-07__s3 {
position: relative;
/* See plx-07__s1 comment above for rationale. */
height: 300vh;
background: #100c08;
}
.plx-07__s3-pin {
position: sticky;
top: 0;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: flex-end;
}
.plx-07__s3-bg {
position: absolute;
inset: -30%;
will-change: transform;
background:
repeating-linear-gradient(
0deg,
rgba(220,140,60,0.0) 0px,
rgba(220,140,60,0.0) 20px,
rgba(220,140,60,0.05) 20px,
rgba(220,140,60,0.05) 21px
),
radial-gradient(ellipse at 60% 45%, rgba(200,100,20,0.3) 0%, transparent 55%),
linear-gradient(160deg, #100c06 0%, #180e04 100%);
}
/* Giant split word */
.plx-07__word-wrap {
position: relative;
z-index: 5;
padding-right: clamp(30px, 8vw, 120px);
will-change: transform;
line-height: 0.88;
}
.plx-07__word-solid {
display: block;
font-family: 'Anton', sans-serif;
font-size: clamp(90px, 20vw, 270px);
letter-spacing: -0.04em;
color: #f4f0e8;
/* clip to top 50% */
clip-path: inset(0 0 50% 0);
line-height: 0.88;
}
.plx-07__word-outline {
display: block;
font-family: 'Anton', sans-serif;
font-size: clamp(90px, 20vw, 270px);
letter-spacing: -0.04em;
color: transparent;
-webkit-text-stroke: 2px rgba(244,240,232,0.4);
/* offset up to align perfectly */
margin-top: calc(clamp(90px, 20vw, 270px) * -0.88);
clip-path: inset(50% 0 0 0);
line-height: 0.88;
}
/* Caption text left side */
.plx-07__s3-caption {
position: absolute;
left: clamp(30px, 6vw, 80px);
bottom: 60px;
z-index: 6;
max-width: 260px;
}
.plx-07__s3-caption h3 {
font-family: 'Lora', serif;
font-style: italic;
font-size: clamp(18px, 2.5vw, 26px);
font-weight: 400;
line-height: 1.4;
margin-bottom: 12px;
}
.plx-07__s3-caption p {
font-size: 13px;
font-weight: 300;
line-height: 1.8;
opacity: 0.45;
}
/* ═══ Footer ═══ */
.plx-07__footer {
background: #f4f0e8;
color: #0c0c0a;
padding: 100px 60px;
text-align: center;
}
.plx-07__footer h2 {
font-family: 'Anton', sans-serif;
font-size: clamp(32px, 6vw, 80px);
letter-spacing: -0.03em;
text-transform: uppercase;
margin-bottom: 20px;
}
.plx-07__footer h2 em {
font-family: 'Lora', serif;
font-style: italic;
font-weight: 400;
color: #b87020;
}
.plx-07__footer p {
font-size: 15px;
font-weight: 300;
line-height: 1.8;
opacity: 0.55;
max-width: 480px;
margin: 0 auto;
}
@media (max-width: 600px) {
.plx-07__s3-caption { display: none; }
}
@media (prefers-reduced-motion: reduce) {
.plx-07__s1-bg, .plx-07__s2-bg, .plx-07__s2-bg, .plx-07__s3-bg,
.plx-07__quote-wrap, .plx-07__word-wrap, .plx-07__display { transform: none !important; }
}(() => {
const s1 = document.querySelector('.plx-07__s1');
const s2 = document.querySelector('.plx-07__s2');
const s3 = document.querySelector('.plx-07__s3');
const s1bg = document.getElementById('plx07-s1-bg');
const line1 = document.getElementById('plx07-line1');
const line2 = document.getElementById('plx07-line2');
const line3 = document.getElementById('plx07-line3');
const s2bg = document.getElementById('plx07-s2-bg');
const quote = document.getElementById('plx07-quote');
const s3bg = document.getElementById('plx07-s3-bg');
const word = document.getElementById('plx07-word');
let ticking = false;
/* progress(el): sticky-pin progress, 0 at pin engage → 1 at pin
release. Uses (offsetHeight - innerHeight) as the divisor which
is the pin runway in scroll px. With scene at 300vh + sticky
inner at 100vh, the runway is 200vh of scroll. */
function progress(el) {
if (!el) return 0;
const r = el.getBoundingClientRect();
const h = el.offsetHeight - window.innerHeight;
return h > 0 ? Math.max(0, Math.min(1, -r.top / h)) : 0;
}
function onScroll() {
if (ticking) return;
ticking = true;
requestAnimationFrame(() => {
// Scene 1: bg scrolls up fast, text drifts slightly
const p1 = progress(s1);
if (s1bg) s1bg.style.transform = `translateY(${p1 * -120}px)`;
if (line1) line1.style.transform = `translateY(${p1 * 15}px)`;
if (line2) line2.style.transform = `translateY(${p1 * 0}px)`;
if (line3) line3.style.transform = `translateY(${p1 * -15}px)`;
// Scene 2: bg scrolls fast, quote drifts slowly upward
const p2 = progress(s2);
if (s2bg) s2bg.style.transform = `translateY(${p2 * -140}px)`;
if (quote) quote.style.transform = `translateY(${p2 * -40}px)`;
// Scene 3: bg scrolls, word barely moves (anchored feel)
const p3 = progress(s3);
if (s3bg) s3bg.style.transform = `translateY(${p3 * -120}px) skewY(${p3 * 1.5}deg)`;
if (word) word.style.transform = `translateY(${p3 * -12}px)`;
ticking = false;
});
}
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
})(); (() => {
const s1 = document.querySelector('.plx-07__s1');
const s2 = document.querySelector('.plx-07__s2');
const s3 = document.querySelector('.plx-07__s3');
const s1bg = document.getElementById('plx07-s1-bg');
const line1 = document.getElementById('plx07-line1');
const line2 = document.getElementById('plx07-line2');
const line3 = document.getElementById('plx07-line3');
const s2bg = document.getElementById('plx07-s2-bg');
const quote = document.getElementById('plx07-quote');
const s3bg = document.getElementById('plx07-s3-bg');
const word = document.getElementById('plx07-word');
let ticking = false;
/* progress(el): sticky-pin progress, 0 at pin engage → 1 at pin
release. Uses (offsetHeight - innerHeight) as the divisor which
is the pin runway in scroll px. With scene at 300vh + sticky
inner at 100vh, the runway is 200vh of scroll. */
function progress(el) {
if (!el) return 0;
const r = el.getBoundingClientRect();
const h = el.offsetHeight - window.innerHeight;
return h > 0 ? Math.max(0, Math.min(1, -r.top / h)) : 0;
}
function onScroll() {
if (ticking) return;
ticking = true;
requestAnimationFrame(() => {
// Scene 1: bg scrolls up fast, text drifts slightly
const p1 = progress(s1);
if (s1bg) s1bg.style.transform = `translateY(${p1 * -120}px)`;
if (line1) line1.style.transform = `translateY(${p1 * 15}px)`;
if (line2) line2.style.transform = `translateY(${p1 * 0}px)`;
if (line3) line3.style.transform = `translateY(${p1 * -15}px)`;
// Scene 2: bg scrolls fast, quote drifts slowly upward
const p2 = progress(s2);
if (s2bg) s2bg.style.transform = `translateY(${p2 * -140}px)`;
if (quote) quote.style.transform = `translateY(${p2 * -40}px)`;
// Scene 3: bg scrolls, word barely moves (anchored feel)
const p3 = progress(s3);
if (s3bg) s3bg.style.transform = `translateY(${p3 * -120}px) skewY(${p3 * 1.5}deg)`;
if (word) word.style.transform = `translateY(${p3 * -12}px)`;
ticking = false;
});
}
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
})();More from 10 CSS Parallax Effects
CSS Parallax Card Hover EffectCSS Zoom-In / Depth Parallax on ScrollCSS Parallax Background Blur TransitionCSS Parallax Hero SectionMulti-layered CSS Parallax Landscape / IllustrationCSS Sticky Parallax SectionsMulti-Scene Parallax ScrollingCSS Parallax Image Grid / GalleryCSS Horizontal Parallax Scroll
View the full collection →