DEV Community

Cover image for Building Scroll-Linked Parallax Effects in Pure Tailwind and Vanilla JavaScript
HexShift
HexShift

Posted on • Edited on

Building Scroll-Linked Parallax Effects in Pure Tailwind and Vanilla JavaScript

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!

Level up your prompt-writing game with Vibe Coding: Prompting Best Practices — a concise, expert-crafted guide covering ten key areas of effective prompt design. Learn to leverage AI more effectively through multi-step reasoning, clear intent framing, and techniques that go beyond trial and error.

Top comments (1)

Collapse
 
nevodavid profile image
Nevo David

been thinking about dropping the big libraries myself so this feels like the move