Background Animation Effect with Next.js

Eugene Musebe

Introduction

This article demonstrates how Javascript and css can be used to create an awesome background ie for a website.

Codesandbox

Check the sandbox demo on Codesandbox.

You can also get the project GitHub repo using Github.

Prerequisites

Entry-level javascript, CSS, and React/Nextjs knowledge.

Setting Up the Sample Project

In your respective folder, create a new net js app using npx create-next-app removePerson in your terminal. Head to your project root directory cd removePerson

We will use Cloudinary for captioning any point of our animated background. That is, in case a user wishes to present a background sample.

Create your own cloudinary account using Link and log into it. Each cloudinary user account will have a dashboard containing environment variable keys that are necessary for the cloudinary integration in our project.

In your project directory, start by including Cloudinary in your project dependencies npm install cloudinary create a new file named .env and paste the following code. Fill the blanks with your environment variables from the cloudinary dashboard.

1".env"
2
3CLOUDINARY_CLOUD_NAME =
4
5CLOUDINARY_API_KEY =
6
7CLOUDINARY_API_SECRET =

Restart your project: npm run dev.

In the pages/api folder, create a new file named upload.js. Start by installing cloudinary npm install cloudinary and configuring the environment keys and libraries.

1"pages/api/upload.js"
2
3
4var cloudinary = require("cloudinary").v2;
5
6cloudinary.config({
7 cloud_name: process.env.CLOUDINARY_NAME,
8 api_key: process.env.CLOUDINARY_API_KEY,
9 api_secret: process.env.CLOUDINARY_API_SECRET,
10});

Include a handler function to receive media file data and post it to the cloudinary website then capture the media file's cloudinary link and send it back as a response.

1"pages/api/upload.js"
2
3
4export default async function handler(req, res) {
5 if (req.method === "POST") {
6 let url = ""
7 try {
8 let fileStr = req.body.data;
9 const uploadedResponse = await cloudinary.uploader.upload_large(
10 fileStr,
11 {
12 chunk_size: 6000000,
13 }
14 );
15 url = uploadedResponse.url
16 } catch (error) {
17 res.status(500).json({ error: "Something wrong" });
18 }
19
20 res.status(200).json({data: url});
21 }
22}

For the front end, we will animate a website background. This article will show 2 kinds of backgrounds. In the pages/index folder, paste the following in the return statement

1"pages/index"
2
3
4 return (
5 <>
6 <div className="item">
7 {link? <h3><b>Uploaded</b></h3>: <h3>Double Click anywhere to save Caption</h3>}
8 </div>
9 <div className="container" onClick={captionHandler}>
10 <div className="heart"></div>
11 </div>
12 </>
13 )

Notice the captionHandler function. We will use it to capture a screenshot of the background effect and send it to the backend for upload. Since the screenshot will be for the whole document body, go ahead and paste the following code.

1"pages/index"
2
3
4 async function captionHandler () {
5 await takeScreenshot(document.body).then(function (caption) {
6 if (!caption) return
7 try {
8 fetch('/api/upload', {
9 method: 'POST',
10 body: JSON.stringify({ data: userprofile }),
11 headers: { 'Content-Type': 'application/json' },
12 })
13 .then((response) => response.json())
14 .then((data) => {
15 setLink(data.data);
16 });
17 } catch (error) {
18 console.error(error);
19 }
20 })
21 }

The code above is meant to capture the document body and post it to the backend as an image file. The code's response will include the media file's cloudinary link which will be saved to a use state hook.

Let us now animate the background. Paste the following code in 'the styles/global" directory.

1html body {
2 text-align: left;
3 object-fit: cover;
4 font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
5 Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
6}
7
8* {
9 margin: 0;
10 padding: 0;
11 box-sizing: 0;
12}
13.item{
14 align-items: center;
15 display: flex;
16 flex-direction: row;
17 /* border: 3px solid rgb(0, 0, 0); */
18 text-align: center;
19 padding: 10px;
20 margin: 10px;
21}
22
23.column {
24 flex: 1 1 0px;
25 border: 10px;
26 /* border:3px solid rgb(182, 0, 0); */
27 text-align: center;
28}
29.container {
30 /* border: 5px solid blue; */
31 position: absolute;
32 top: 0;
33 left: 50;
34 width: 100%;
35 height: 100vh;
36 display: flex;
37 justify-content: center;
38 align-items: center;
39 background-image: #e80202;
40 overflow: hidden
41}
42
43.heart {
44 position: absolute;
45 width: 40px;
46 height: 40px;
47 background: transparent;
48 transform: rotate(45deg);
49 box-shadow: 0 -20px 20px rgba(0, 0, 0, 0.1);
50}
51
52.heart::before {
53 content: '';
54 position: absolute;
55 top: -50%;
56 left: 0%;
57 width: 100%;
58 height: 100%;
59 background: #e80202;
60 border-radius: 50%;
61 box-shadow: -20px 0 20px rgba(0, 0, 0, 0.1);
62}
63
64.heart::after {
65 content: '';
66 position: absolute;
67 top: 0;
68 left: -50%;
69 width: 100%;
70 height: 100%;
71 background: transparent;
72 border-radius: 50%;
73 box-shadow: -20px 0 20px rgba(0, 0, 0, 0.1);
74}
75
76button {
77 padding: 15px;
78 color: #7B7B7B;
79 background-color: #FFF;
80 border-radius: 1rem;
81 border: 1px solid;
82 font-size: 20px;
83 width: 200px;
84 height: 60px;
85 align-items: center;
86 text-align: center;
87}
88button:hover {
89 transform: translateY(-3px);
90 transition: 1s;
91 box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
92}

The css code above will create a heart-like div that rotates randomly on the screen. We will however need to tweak it at this level to make it more appealing. Such will be achieved through a useEffect hook and an animaheHandler function. We use animejs to achieve this.

npm install animejs

1import anime from 'animejs';
2
3 useEffect(() => {
4 const container = document.querySelector('.container');
5
6 for (var i = 1; i <= 50; i++) {
7 const hearts = document.createElement('div');
8 hearts.classList.add('heart')
9 container.appendChild(hearts);
10 }
11
12 animateHearts()
13 }, [])
14
15 function animateHearts() {
16 anime({
17 targets: '.heart',
18 translateX: function (x) {
19 return anime.random(-700, 700);
20 },
21 translateY: function (x) {
22 return anime.random(-500, 500);
23 },
24 rotate: 45,
25 scale: function () {
26 return anime.random(1, 5)
27 },
28 easing: 'easeInOutBack',
29 duration: 3000,
30 delay: anime.stagger(10),
31 complete: animateHearts,
32 })
33 }

That's it. If u run your code at this point you should have a richly animated background that loops through animated effects. Ensure to go through this article to enjoy the experience.

Eugene Musebe

Software Developer

I’m a full-stack software developer, content creator, and tech community builder based in Nairobi, Kenya. I am addicted to learning new technologies and loves working with like-minded people.