profile picture of Olivier Larose

Olivier Larose

May 25, 2024

/

Beginner

/

Short

Text Parallax

How to Create a Text Parallax Animation with React and Framer Motion

A website animation featuring a Text Parallax with sliding text on scroll, made with Framer Motion and React, inside a Next.js app

Live DemoSource code
background video

Creating the Project

Let's start the project by creating a Next.js application. We can do that by running npx create-next-app@latest client inside of a terminal.

  • We will use Framer Motion for the animation, so we can run npm i framer-motion.
  • We will use the Lenis Scroll for the smooth scrolling, so we can run npm i lenis.

Creating 3 Slides

Here I'll create 3 slides with a certain left position to randomize the layout.

  • I initialize a Lenis scroll to have a smooth scroll
  • I use an overflow:hidden on the parent to remove the horizontal scroll created by the long slides.

page.js

1

'use client'

2

import Picture1 from '../../public/images/1.jpg'

3

import Picture2 from '../../public/images/2.jpg'

4

import Picture3 from '../../public/images/3.jpg'

5

import Lenis from 'lenis';

6

import Image from 'next/image';

7

import { useEffect } from 'react';

8

9

export default function Home() {

10

11

useEffect( () => {

12

const lenis = new Lenis()

13

14

function raf(time) {

15

lenis.raf(time)

16

requestAnimationFrame(raf)

17

}

18

19

requestAnimationFrame(raf)

20

}, [])

21

22

return (

23

<main className='overflow-hidden'>

24

<div className='h-[100vh]'/>

25

<Slide src={Picture1} left={"-40%"}/>

26

<Slide src={Picture2} left={"-25%"}/>

27

<Slide src={Picture3} left={"-75%"}/>

28

<div className='h-[100vh]' />

29

</main>

30

);

31

}

The slides all contain 3 phrases inside of them:

Here the magic property is the white-space set at nowrap. This allows the 3 phrases to overflow outside the container and create a long slide larger than the width of the viewport.

page.js

1

const Slide = (props) => {

2

return (

3

<div style={{left: props.left}} className="relative flex whitespace-nowrap">

4

<Phrase src={props.src}/>

5

<Phrase src={props.src}/>

6

<Phrase src={props.src}/>

7

</div>

8

)

9

}

10

11

const Phrase = ({src}) => {

12

return (

13

<div className={'px-5 flex gap-5 items-center'}>

14

<p className='text-[7.5vw]'>Front End Developer</p>

15

<span className="relative h-[7.5vw] aspect-[4/2] rounded-full overflow-hidden">

16

<Image style={{objectFit: "cover"}} src={src} alt="image" fill/>

17

</span>

18

</div>

19

)

20

}

We should have something like this:

Tracking the progress of the Scroll

Here I'll use a mix of the useScroll and the useTransform hook from Framer Motion.

The first thing I need to do is track the progress of the scroll, then I can give the progresss of the sroll and a certain direction to each slide.

page.js

1

export default function Home() {

2

3

const container = useRef();

4

const { scrollYProgress } = useScroll({

5

target: container,

6

offset: ['start end', 'end start']

7

})

8

...

9

return (

10

<main className="overflow-hidden">

11

<div className='h-[100vh]'/>

12

<div ref={container}>

13

<Slide src={Picture1} direction={'left'} left={"-40%"} progress={scrollYProgress}/>

14

<Slide src={Picture2} direction={'right'} left={"-25%"} progress={scrollYProgress}/>

15

<Slide src={Picture3} direction={'left'} left={"-75%"} progress={scrollYProgress}/>

16

</div>

17

<div className='h-[100vh]' />

18

</main>

19

);

20

}

Moving the Slides on Scroll

Once I have access to the progress of the scroll and a certain direction, I can use all of that inside the useTransform hook to translate the phrases on scroll.

page.js

1

const Slide = (props) => {

2

const direction = props.direction == 'left' ? -1 : 1;

3

const translateX = useTransform(props.progress, [0, 1], [150 * direction, -150 * direction])

4

5

return (

6

<motion.div style={{x: translateX, left: props.left}} className="relative flex whitespace-nowrap">

7

<Phrase src={props.src}/>

8

<Phrase src={props.src}/>

9

<Phrase src={props.src}/>

10

</motion.div>

11

)

12

}

We should have something like this:

Wrapping up

That's it for this animation!

A very common animation that adds a little extra to any website, hope you learned something!

-Oli

Related Animations

image

June 2, 2024

Mask Section Transition

A website tutorial featuring a scroll animation using an SVG Mask to create a section transition, made with React, Framer Motion. Inspired by: https://axelvanhessche.com/. Pictures by Eric Asamoah, Inka and Niclas Lindergård, Daniel Ribar

image

May 25, 2024

Background Image Parallax

A website animation featuring a background image moving on scroll in a parallax motion, made with Framer Motion and React, inside a Next.js app. Inspired by: https://inkfishnyc.com/. Pictures by Matthias Leidinger

image

May 21, 2024

Sticky Footer

A website tutorial featuring a sticky footer animation with a reveal effect, made with position fixed and sticky using React and CSS.