Parallax scrolling — where elements move at different speeds relative to scrolling — can make a website feel deeply dynamic. Most people use heavy libraries like GSAP for this. But today, we’ll build a clean, efficient scroll-linked parallax effect with just Tailwind CSS and vanilla JavaScript. No external dependencies.
Why Go Pure?
Benefits include:
- Massively reduced page weight
- Customizable to any design system
- Better performance for mobile users
Step 1: Create Your Layers
Each parallax layer gets a basic Tailwind setup:
<section class="relative h-[200vh] overflow-hidden">
<div class="absolute top-0 left-0 w-full h-full" data-parallax data-speed="0.3">
<img src="/background-layer.jpg" class="w-full h-full object-cover" />
</div>
<div class="absolute top-0 left-0 w-full h-full" data-parallax data-speed="0.6">
<img src="/midground-layer.png" class="w-full h-full object-cover opacity-80" />
</div>
<div class="relative z-10 flex items-center justify-center h-screen">
<h1 class="text-6xl font-bold text-white">Scroll Down</h1>
</div>
</section>
Step 2: Basic JavaScript for Parallax
This snippet calculates parallax based on scroll position:
<script>
const parallaxEls = document.querySelectorAll('[data-parallax]');
window.addEventListener('scroll', () => {
const scrollTop = window.pageYOffset;
parallaxEls.forEach(el => {
const speed = parseFloat(el.getAttribute('data-speed'));
el.style.transform = `translateY(${scrollTop * speed}px)`;
});
});
</script>
Step 3: Tuning Speeds Per Layer
You can assign different speeds to different layers with data-speed
. Smaller values (e.g., 0.1) move slower (background feel), larger values (e.g., 0.6) move faster (foreground feel).
Bonus: Smoother Motion with requestAnimationFrame
For buttery smoothness, swap in a rAF loop instead of basic scroll event:
<script>
let latestScroll = 0;
let ticking = false;
window.addEventListener('scroll', () => {
latestScroll = window.pageYOffset;
if (!ticking) {
window.requestAnimationFrame(() => {
parallaxEls.forEach(el => {
const speed = parseFloat(el.getAttribute('data-speed'));
el.style.transform = `translateY(${latestScroll * speed}px)`;
});
ticking = false;
});
ticking = true;
}
});
</script>
Pros and Cons
✅ Pros
- No libraries — maximum control and minimal load time
- Fully responsive and easy to tweak per element
- Compatible with Tailwind’s utility-first workflow
⚠️ Cons
- Manual math if you want more complex motion curves
- Very fast scrolls might cause tiny visual tearing without fine-tuning
🚀 Alternatives
- Locomotive Scroll: Adds inertia and smooth-scroll parallax but is a heavy dependency
- GSAP ScrollTrigger: Amazing for animation timelines, but overkill if you only want basic parallax
Summary
Creating scroll-linked parallax in Tailwind and vanilla JavaScript is refreshingly simple and surprisingly powerful. With just a few utility classes and event listeners, you can add rich motion to your site without slowing it down — a massive win for modern frontend builds!
If you found this useful, you can support me here: buymeacoffee.com/hexshift
Top comments (1)
been thinking about dropping the big libraries myself so this feels like the move