Advanced Scroll Direction-Aware Animations in Tailwind CSS (No Libraries Needed)

Most scroll-triggered animations treat upward and downward scrolls the same — but what if you could animate *differently* based on scroll direction? This technique gives your UI a polished, professional feel without needing heavy libraries. Let's go beyond basic IntersectionObserver and build scroll direction-aware animations using Tailwind CSS and native JavaScript. Why Care About Scroll Direction? Reacting to scroll direction enables: Elements that slide up when scrolling up, and fade down when scrolling down More natural "reveal" animations that match user intent Advanced UX patterns like smart sticky headers or timeline reveals Step 1: Extend Tailwind for More Animation Variants We'll define upward and downward animations separately: // tailwind.config.js module.exports = { theme: { extend: { keyframes: { fadeSlideUp: { '0%': { opacity: 0, transform: 'translateY(20px)' }, '100%': { opacity: 1, transform: 'translateY(0)' }, }, fadeSlideDown: { '0%': { opacity: 0, transform: 'translateY(-20px)' }, '100%': { opacity: 1, transform: 'translateY(0)' }, }, }, animation: { fadeSlideUp: 'fadeSlideUp 0.8s ease-out forwards', fadeSlideDown: 'fadeSlideDown 0.8s ease-out forwards', }, }, }, } Step 2: Markup with Hidden Defaults Set your elements to start hidden and slightly offset: Scroll-Direction Aware Element Step 3: Create a Scroll Direction Tracker We track scroll position changes to determine direction: let lastScrollY = window.scrollY; let scrollDirection = 'down'; window.addEventListener('scroll', () => { const currentScrollY = window.scrollY; scrollDirection = currentScrollY > lastScrollY ? 'down' : 'up'; lastScrollY = currentScrollY; }); Step 4: Set Up IntersectionObserver With Direction Logic Combine IntersectionObserver and our scroll direction state: const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.remove('opacity-0'); if (scrollDirection === 'down') { entry.target.classList.add('animate-fadeSlideUp'); } else { entry.target.classList.add('animate-fadeSlideDown'); } observer.unobserve(entry.target); } }); }, { threshold: 0.2, }); document.querySelectorAll('[data-animate]').forEach(el => observer.observe(el)); Now the animation direction dynamically matches the user's scroll intent! Pros and Cons ✅ Pros Zero external libraries required Professional, dynamic feel with simple code Extremely lightweight for high-performance web apps ⚠️ Cons Only triggers once per element (could add re-entry logic if needed) Needs a little extra logic for fast scrolls or edge cases

Apr 27, 2025 - 05:50
 0
Advanced Scroll Direction-Aware Animations in Tailwind CSS (No Libraries Needed)

Most scroll-triggered animations treat upward and downward scrolls the same — but what if you could animate *differently* based on scroll direction? This technique gives your UI a polished, professional feel without needing heavy libraries. Let's go beyond basic IntersectionObserver and build scroll direction-aware animations using Tailwind CSS and native JavaScript.

Why Care About Scroll Direction?

Reacting to scroll direction enables:

  • Elements that slide up when scrolling up, and fade down when scrolling down
  • More natural "reveal" animations that match user intent
  • Advanced UX patterns like smart sticky headers or timeline reveals

Step 1: Extend Tailwind for More Animation Variants

We'll define upward and downward animations separately:

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      keyframes: {
        fadeSlideUp: {
          '0%': { opacity: 0, transform: 'translateY(20px)' },
          '100%': { opacity: 1, transform: 'translateY(0)' },
        },
        fadeSlideDown: {
          '0%': { opacity: 0, transform: 'translateY(-20px)' },
          '100%': { opacity: 1, transform: 'translateY(0)' },
        },
      },
      animation: {
        fadeSlideUp: 'fadeSlideUp 0.8s ease-out forwards',
        fadeSlideDown: 'fadeSlideDown 0.8s ease-out forwards',
      },
    },
  },
}

Step 2: Markup with Hidden Defaults

Set your elements to start hidden and slightly offset:

Scroll-Direction Aware Element

Step 3: Create a Scroll Direction Tracker

We track scroll position changes to determine direction:


Step 4: Set Up IntersectionObserver With Direction Logic

Combine IntersectionObserver and our scroll direction state:


Now the animation direction dynamically matches the user's scroll intent!

Pros and Cons

✅ Pros

  • Zero external libraries required
  • Professional, dynamic feel with simple code
  • Extremely lightweight for high-performance web apps

⚠️ Cons

  • Only triggers once per element (could add re-entry logic if needed)
  • Needs a little extra logic for fast scrolls or edge cases