profile picture of Olivier Larose

Olivier Larose

May 7, 2023

/

Beginner

/

Short

Text Mask Animation

How to use a mask to animate HTML text when in view using React, Framer Motion and Next.js

An animation featuring a text sliding effect with a mask, to give the effect of text gradually appearing when in view. Made with React and Framer Motion in a Next.js environment.

Live DemoSource codeVideo Tutorial
background video

Initializing 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.

Adding the HTML and CSS

We can delete everything in the page.js , global.css and page.module.css and add our own HTML and CSS, to start with a nice blank application.

page.js

page.mod...

1

'use client'

2

import styles from './page.module.css'

3

4

const phrases = [

5

"It is a long established fact",

6

"that a reader will be distracted",

7

"by the readable content of a page",

8

"when looking at its layout."

9

]

10

11

export default function Home() {

12

return (

13

<div className={styles.container}>

14

<MaskText/>

15

<MaskText/>

16

<MaskText/>

17

<MaskText/>

18

<MaskText/>

19

</div>

20

)

21

}

22

23

export function MaskText() {

24

return(

25

<div className={styles.body}>

26

{

27

phrases.map( (phrase, index) => {

28

return <div key={index} className={styles.lineMask}>

29

<p>{phrase}</p>

30

</div>

31

})

32

}

33

</div>

34

)

35

}

36

Nothing too complicated here, we map the phrases and return a div for each of of them.

We should have something like this

Detect when in view

Before animating the text, we need to find a way to detect when the text is inside the viewport, so that only then we will animate the text.

To do that, we're going to use the useInView hook from Framer-Motion. To install it, we can run npm i framer-motion

page.js

1

import { useInView } from 'react-intersection-observer';

2

...

3

export function MaskText() {

4

5

const body = useRef(null);

6

const isInView = useInView(body, {once: true, margin: "75%"})

7

8

return(

9

<div ref={body} className={styles.body}>

10

...
  • margin:"75%" We wait until the body is visible by 75% before considering it to be in view.

With that in place, we can now detect when the text is in view, and animate in consequence.

Animate in

For the animation, we will use Framer-Motion, but you could use anything like GSAP or even pure CSS.

We can create a new animation variant that will manipule the y attribute of our the text.

page.js

page.mod...

1

import { useRef } from 'react';

2

import { useInView, motion } from 'framer-motion';

3

...

4

5

export function MaskText() {

6

7

const body = useRef(null);

8

const isInView = useInView(body, {once: true, margin: "-75%"})

9

10

const animation = {

11

initial: {y: "100%"},

12

enter: i => ({y: "0", transition: {duration: 0.75, ease: [0.33, 1, 0.68, 1], delay: 0.075 * i}})

13

}

14

15

return(

16

<div ref={body} className={styles.body}>

17

{

18

phrases.map( (phrase, index) => {

19

return <div key={index} className={styles.lineMask}>

20

<motion.p custom={index} variants={animation} initial="initial" animate={isInView ? "enter" : ""}>{phrase}</motion.p>

21

</div>

22

})

23

}

24

</div>

25

)

26

}

27

Here's a couple of important things to note:

  • We add overflow:hidden to the div that encapsulates the div, so that all children will be invisibile outside of its bounds.
  • We create a new animation variant that initially set the y property of the text at 100%.
  • When the text comes in view, isInView becomes true, triggering the animation and thus setting the y property at 0%.
  • The custom attribute is used to transfer the index and create a delay in the animation between the different phrases.

And that's it! You should see this:

Wrapping up

That was it for this animation, it's a very common animation that I find inside of a lot of awwwards winning animation. It's a pretty simple concept, but good to have inside of our toolbox.

Hope you learned a lot :)

-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 25, 2024

Text Parallax

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