CSS Loader Animation Effect

Eugene Musebe

Introduction

Animations are necessary to create models that are essential for research and study. We’ll use css and js framework to show an example of how a loader can be animated and captions uploaded where necessary. We design the loader components using css and animate them through Nextjs and animejs library.

Codesandbox

The final version of this project can be viewed on Codesandbox.

You can find the full source code on my Github repo.

Prerequisites

Basic/entry-level knowledge and understanding of javascript and React/Nextjs.

Setting Up the Sample Project

Create your project root directory: npx create-next-app loader

Enter the directory: cd loader

In our project, let us have a backend for online media file upload. This will help users capture a caption of the loader and store it online for those who will want to showcase their project results. We'll use Cloudinary for this feature.

Include Cloudinary in your project dependencies: npm install cloudinary

Use this link to create or log into your Cloudinary account. You will be provided with a dashboard containing the necessary environment variables for integration.

In your root directory, create a new file named .env.local and use the following guide to fill your dashboard's variables.

1CLOUDINARY_CLOUD_NAME =
2
3CLOUDINARY_API_KEY =
4
5CLOUDINARY_API_SECRET=

Restart your project: npm run dev.

Create another directory pages/api/upload.js.

Configure the environment keys and libraries.

1var cloudinary = require("cloudinary").v2;
2
3cloudinary.config({
4 cloud_name: process.env.CLOUDINARY_NAME,
5 api_key: process.env.CLOUDINARY_API_KEY,
6 api_secret: process.env.CLOUDINARY_API_SECRET,
7});

Finally, add a handler function to execute Nextjs post request:

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

The above function will upload the request body containing media files to Cloudinary and return the captioned result in form of a Cloudinary link as a response

We can now work on our front end. There is not much required in the front end. First, Paste the following code into the home component.

1<>
2 <nav>
3 <h2>CSS Loader Animation Effect</h2>
4 <button>Upload</button>
5 </nav>
6
7 <div id="boxes" ref={containerRef}>
8 <div className="box red"></div>
9 <div className="box blue"></div>
10 <div className="box green"></div>
11 <div className="box cyan"></div>
12 </div>
13</>

We create a nav bar containing the project title and a button and a container boxes, containing 4 box containers. Each container can be filled with a color of your choice. We will want each of them to have separate colors as well and separate animations at different times. Use the following code in your CSS.

1"styles/global.css"
2
3nav{
4 width: 100vw;
5 display:flex;
6 flex-wrap: wrap;
7 justify-content: space-between;
8 align-items: center;
9 background: #FFF;
10 padding: 10px;
11}
12h2{
13 color: black;;
14}
15a {
16 color: inherit;
17 text-decoration: none;
18}
19
20#boxes {
21 display: flex;
22 text-align: center;
23 align-items: center;
24 height: 100vh;
25 justify-content: center;
26 overflow: hidden;
27}
28
29#btns {
30 padding: 25px;
31 background: white;
32 margin-bottom: 40px;
33}
34
35#btns button {
36 background: white;
37 padding: 5px 10px;
38 border: 0px;
39}
40
41#btns .fa {
42 font-size: 30px;
43 color: #0078d7;
44}
45
46
47.box {
48 position: relative;
49 width: 60px;
50 height: 60px;
51 margin: 4px;
52 display: inline-block;
53}
54
55.red {
56 background-color: #1e4f3c;
57}
58.blue {
59 background-color: #af151a;
60}
61.green {
62 background-color: #480fe6;
63}
64.cyan {
65 background-color: #06c22f;
66}

So far your result should look like the below:

Include animejs in your dependencies: npm install animejs --save

Import it into your home component and introduce it to your home function through a useEffect state hook.

1"pages/index.js"
2
3import html2canvas from "html2canvas";
4import {useEffect} from "react";
5import anime from 'animejs';
6
7
8export default function Home() {
9 const containerRef = useRef();
10
11
12
13 useEffect(() => {
14 anime ({
15 targets: 'div.box',
16 translateY: [
17 {value: 200, duration: 500},
18 {value:0, duration: 800}
19 ],
20 rotate: {
21 value: '1turn',
22 },
23 borderRadius: 50,
24 direction: 'alternate',
25 easing: 'easeInOutQuad',
26 delay: function() { return anime.random(0, 1000); },
27 // autoplay: false,
28 loop: true,
29 elasticity: 200
30
31 });
32
33 })
34 return (
35 <>
36 <nav>
37 <h2>CSS Loader Animation Effect</h2>
38 <button >Upload</button>
39 </nav>
40
41 <div id="boxes">
42 <div className="box red"></div>
43 <div className="box blue"></div>
44 <div className="box green"></div>
45 <div className="box cyan"></div>
46 </div>
47 </>
48 )
49};

By now, you have already noticed changes in the way the boxes animate themselves. In the anime function parameters above, target is used to reference the div element class to animate. translateY displaces the shapes along the Y-axis. Both value and duration specify the coordinate at which the shape will get displaced and how many milliseconds it should maintain at that point. We then allow the animation to continue in a loop. We will also include rotation and morph the border-radius to a circle parameter to make it look better. The direction is set to alternate to change direction in each loop. The easing controls the rate at which active animation is played. The delay param contains a function returning a random value for the loop param and we finally include the elasticity param which means the animation won’t stop abruptly once it’s done but oscillates instead.

The final part will be to allow captioning of our loader for online storage. Edit the home component to look like the below:

1"pages/index/js"
2
3import html2canvas from "html2canvas";
4import {useRef, useState, useEffect} from "react";
5import anime from 'animejs';
6
7
8export default function Home() {
9 const containerRef = useRef();
10 const [link, setLink] = useState('');
11
12
13 const uploadHandler = async() => {
14 await html2canvas(containerRef.current).then(function(canvas) {
15 console.log(canvas.toDataURL());
16 })
17 }
18
19 useEffect(() => {
20 anime ({
21 targets: 'div.box',
22 translateY: [
23 {value: 200, duration: 500},
24 {value:0, duration: 800}
25 ],
26 rotate: {
27 value: '1turn',
28 },
29 borderRadius: 50,
30 direction: 'alternate',
31 easing: 'easeInOutQuad',
32 delay: function() { return anime.random(0, 1000); },
33 // autoplay: false,
34 loop: true,
35 elasticity: 200
36
37 });
38
39 })
40 return (
41 <>
42 <nav>
43 <h2>CSS Loader Animation Effect</h2>
44 {link && <a href={link}><h3>Caption</h3></a>}
45 <button onClick={uploadHandler}>Upload</button>
46 </nav>
47
48 <div id="boxes" ref={containerRef}>
49 <div className="box red"></div>
50 <div className="box blue"></div>
51 <div className="box green"></div>
52 <div className="box cyan"></div>
53 </div>
54 </>
55 )
56};

The code above captions a frame in the div, referenced using the useRef hook, and sends it to the backend for upload and a canvas URL string using html2canvas. Once the response is ready, It is displayed to the front end using a useState hook.

That completes the project. Have fun playing with this example on your website.

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.