Animated Scroll Effects in React

Loading

Adding scroll-based animations can greatly enhance the user experience by creating interactive, visually appealing effects as users scroll through a page. React, combined with libraries like React Spring or Framer Motion, allows you to easily implement animated scroll effects.

In this guide, we will show you how to create animated scroll effects in React, where elements will animate based on the user’s scroll position.

1. Setting Up the Project

If you haven’t already, create a React project and install the necessary animation library. We will use React Spring for this example, but Framer Motion could also be a good alternative.

Install React Spring:

npm install @react-spring/web

or with yarn:

yarn add @react-spring/web

2. Simple Scroll Fade-in Animation

The most common scroll effect is fading in content as the user scrolls to a certain position. We’ll use React Spring‘s useSpring and animated components to create this effect.

Example: Fade-in Animation Based on Scroll Position

import React, { useState, useEffect } from 'react';
import { useSpring, animated } from '@react-spring/web';

const ScrollFadeIn = () => {
  const [isVisible, setIsVisible] = useState(false);

  const handleScroll = () => {
    const scrollPosition = window.scrollY;
    // Show the element when the user has scrolled down 200px
    if (scrollPosition > 200) {
      setIsVisible(true);
    } else {
      setIsVisible(false);
    }
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  const fadeInStyle = useSpring({
    opacity: isVisible ? 1 : 0,
    transform: isVisible ? 'translateY(0)' : 'translateY(50px)',
    config: { tension: 170, friction: 26 },
  });

  return (
    <animated.div style={fadeInStyle} className="fade-in">
      <h2>This will fade in when you scroll!</h2>
    </animated.div>
  );
};

export default ScrollFadeIn;

Explanation:

  • useSpring: The hook defines the animation for the element. The element will fade in and slide up (translateY(0)) when it becomes visible.
  • useEffect: This listens for the scroll event. When the scroll position exceeds 200px, it sets the element to be visible and animates it.
  • animated.div: This component is animated with the styles returned by useSpring.

3. Scroll Animations with useSprings for Multiple Elements

If you want to animate a list of items or multiple elements on scroll, you can use useSprings, which allows you to animate multiple items simultaneously.

Example: Fade-In Multiple Items on Scroll

import React, { useState, useEffect } from 'react';
import { useSprings, animated } from '@react-spring/web';

const ScrollList = () => {
  const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];

  const [isVisible, setIsVisible] = useState(Array(items.length).fill(false));

  const handleScroll = () => {
    const scrollPosition = window.scrollY;
    const newVisibility = items.map((_, index) => scrollPosition > (index + 1) * 150);
    setIsVisible(newVisibility);
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  const springs = useSprings(
    items.length,
    items.map((_, index) => ({
      opacity: isVisible[index] ? 1 : 0,
      transform: isVisible[index] ? 'translateY(0)' : 'translateY(50px)',
      config: { tension: 170, friction: 26 },
    }))
  );

  return (
    <div>
      {springs.map((style, index) => (
        <animated.div key={index} style={style} className="scroll-item">
          {items[index]}
        </animated.div>
      ))}
    </div>
  );
};

export default ScrollList;

Explanation:

  • useSprings: This hook creates animations for multiple elements. It takes an array of animations, each of which corresponds to one element.
  • isVisible: This state tracks whether each item should be visible based on the scroll position. Each item becomes visible after scrolling past its threshold.

4. Scroll-based Parallax Effect

A parallax effect gives the illusion of different layers moving at different speeds. This can be achieved by modifying an element’s position based on scroll speed.

Example: Parallax Scroll Effect

import React, { useState, useEffect } from 'react';
import { useSpring, animated } from '@react-spring/web';

const ParallaxEffect = () => {
  const [scrollPosition, setScrollPosition] = useState(0);

  const handleScroll = () => {
    setScrollPosition(window.scrollY);
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  const parallaxStyle = useSpring({
    transform: `translateY(${scrollPosition * 0.3}px)`, // Moves slower than the scroll
  });

  return (
    <animated.div style={parallaxStyle} className="parallax">
      <h2>This element moves slower than the scroll</h2>
    </animated.div>
  );
};

export default ParallaxEffect;

Explanation:

  • scrollPosition: The scroll position is tracked, and we adjust the translation of the element based on the scroll position.
  • Parallax Effect: The element moves slower than the scroll itself (using a multiplier of 0.3), creating a parallax effect.

5. Scroll-triggered Slide-in Animation

Another popular effect is having elements slide in from the sides or bottom as the user scrolls down the page.

Example: Slide-in from the Bottom on Scroll

import React, { useState, useEffect } from 'react';
import { useSpring, animated } from '@react-spring/web';

const ScrollSlideIn = () => {
  const [isVisible, setIsVisible] = useState(false);

  const handleScroll = () => {
    const scrollPosition = window.scrollY;
    // Show the element when the user has scrolled down 300px
    if (scrollPosition > 300) {
      setIsVisible(true);
    } else {
      setIsVisible(false);
    }
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  const slideInStyle = useSpring({
    transform: isVisible ? 'translateY(0)' : 'translateY(100px)',
    opacity: isVisible ? 1 : 0,
    config: { tension: 170, friction: 26 },
  });

  return (
    <animated.div style={slideInStyle} className="slide-in">
      <h2>This slides in when you scroll!</h2>
    </animated.div>
  );
};

export default ScrollSlideIn;

Explanation:

  • useSpring: The element slides in from below when the user scrolls past 300px, using the transform property.
  • opacity: The element also fades in as it slides into view.

Leave a Reply

Your email address will not be published. Required fields are marked *