Adding a confetti effect to a website usually implies installing a package. What if we could create one for ourselves using nothing but pure, unadulterated CSS and HTML? Well, we’re going to do just that!
In this article, we are going to learn how to create a confetti effect with CSS. We’ll go over how to make different shapes, including squares, rectangles, hexagrams, pentagrams, decagrams, and wavy lines in CSS, as well as learn to animate the shapes and randomize their characteristics to create a confetti effect.
The first thing we are going to do is create a folder on our machine. I called mine app
, but you are free to name yours the way you like.
Open the folder with the code editor of your choice. Next, create two files inside the folder named index.html
and style.css
.
The index.html
file will have this starter markup:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="style.css" /> <title>Confetti</title> </head> <body> <label for="check">Check to stop</label> <input type="checkbox" id="check" /> <div class="confetti-container"> <div class="confetti"> <i class="square"></i> <i class="rectangle"></i> <i class="hexagram"></i> <i class="pentagram"></i> <i class="dodecagram"></i> <i class="wavy-line"></i> </div> </div> </body> </html>
In the markup above, we have some meta tags, a title, and a link to our CSS file in the head
tag. The body element contains a label and a check box that will only be used for demonstration purposes.
The confetti-container
class contains the confetti
, and the confetti
contains various i
tags with classes that match the shapes we will create.
To create the different styles of the confetti, we will open the style.css
file.
Before we create the shapes, the first elements to target are root
, body
, html
, label
, and input
. We will add the following styles to root
and html
:
:root { --bg: yellow; } html, body { background-color: #101e35; font-size: 10px; /* Makes 1rem = 10px */ }
The label
and input
come next:
label { color: white; font-size: 1.5rem; } input { width: 40px; height: 40px; cursor: pointer; }
And then we set the following styles for .confetti-container
and .confetti
:
.confetti-container { user-select: none; pointer-events: none; z-index: 10; } .confetti { position: fixed; left: 0; right: 0; display: flex; }
Let’s break this down a bit.
user-select
and pointer-events
ensure that the content of .confetti-container
cannot be highlighted by the user.
Then, z-index
ensures that the content of the .confetti-container
remains above every element on the page.
The style in .confetti
ensures that the confetti will behave separately from the other content on the page. The display
is set to ensure that the content of .confetti
is always stacked horizontally.
Now, we’ll go over how to create different shapes for our confetti effect. We do this to help add some variety to the confetti effect!
To create a square, we will select the .square
class and add the following style to it:
.confetti .square { width: 1rem; height: 1rem; background-color: var(--bg); transform: rotate(140deg); }
var(--bg)
is an example of a CSS variable. This was set in the :root
, however, it will also be set directly in the HTML in each shape.
The transform
property is used to rotate the square.
A rectangle is similar to a square, however, the width and height won’t be the same. The following styles will generate a rectangle:
.confetti .rectangle { width: 1rem; height: 0.5rem; background-color: var(--bg); }
.hexagram
is a star that has six sides. The following code will generate one for us:
.confetti .hexagram { width: 0; height: 0; border-left: 0.5rem solid transparent; border-right: 0.5rem solid transparent; border-bottom: 1rem solid var(--bg); position: relative; } .confetti .hexagram:after { content: ""; width: 0; height: 0; border-left: 0.5rem solid transparent; border-right: 0.5rem solid transparent; border-top: 1rem solid var(--bg); position: absolute; top: 0.33rem; left: -0.5rem; }
In .confetti .hexagram
, setting the width and height to 0
, as well as setting the borders in the same manner, ensure that we generate a triangle. The position
element makes sure that the properties within it can be moved independently.
In .confetti .hexagram:after
, we generate another triangle that is reversed. And with the position
set to absolute
, we can set the values for top
and left
to correctly position and form a six-sided star.
To create a pentagram, we need to make a five-sided star. To do so, we will add the following styles to .pentagram
:
.confetti .pentagram { width: 0rem; height: 0rem; display: block; margin: 0.5rem 0; border-right: 1rem solid transparent; border-bottom: 0.7rem solid var(--bg); border-left: 1rem solid transparent; transform: rotate(35deg); position: relative; } .confetti .pentagram:before { border-bottom: 0.8rem solid var(--bg); border-left: 0.3rem solid transparent; border-right: 0.3rem solid transparent; position: absolute; height: 0; width: 0; top: -0.45rem; left: -0.65rem; display: block; content: ""; transform: rotate(-35deg); } .confetti .pentagram:after { position: absolute; display: block; color: var(--bg); top: 0.03rem; left: -1.05rem; width: 0rem; height: 0rem; border-right: 1rem solid transparent; border-bottom: 0.7rem solid var(--bg); border-left: 1rem solid transparent; transform: rotate(-70deg); content: ""; }
Let’s break it down.
.confetti .pentagram
generates a triangle and rotates it by 35deg
.
.confetti .pentagram:before
generates a triangle as well and rotates it by -35deg
. The position
was set to move the elements vertically and horizontally.
.confetti .pentagram:after
generates another triangle and rotates it by 70deg
. Additionally, the position
was used to move the top and bottom
displacement.
A dodecagram is a 12-sided star. It combines squares to form its shape. Let’s build it within our .dodecagram
element:
.confetti .dodecagram { background: var(--bg); width: 8px; height: 8px; position: relative; } .confetti .dodecagram:before { content: ""; height: 8px; width: 8px; background: var(--bg); transform: rotate(30deg); position: absolute; top: 0; left: 0; } .confetti .dodecagram:after { content: ""; height: 8px; width: 8px; background: var(--bg); transform: rotate(60deg); position: absolute; top: 0; left: 0; }
.confetti .dodecagram
generates a square, but confetti .dodecagram:before
and .confetti .dodecagram:after
generate two rotated squares.
To create our .wavy-line
element, we will write the following code:
.confetti .wavy-line { position: relative; } .confetti .wavy-line::after, .confetti .wavy-line::before { content: ""; height: 10px; width: 80px; background-size: 20px 10px; position: absolute; left: -9rem; transform: rotate(90deg); } .confetti .wavy-line::before { background-image: linear-gradient( 45deg, transparent, transparent 50%, var(--bg) 50%, transparent 60% ); top: 1rem; } .confetti .wavy-line::after { background-image: linear-gradient( -45deg, transparent, transparent 50%, var(--bg) 50%, transparent 60% ); }
Let’s go over this in more detail.
.confetti .wavy-line
was used to set a relative position to its content.
In .confetti .wavy-line::after
and .confetti .wavy-line::before, background-size
is used to specify the horizontal and vertical size of the pseudo-element.
background-image
was then used to draw the lines with their specific angles.
To animate the shapes and make them simulate a waterfall, we will add the following styles:
.confetti i { width: 3rem; height: 3rem; margin: 0 0.2rem; animation-name: confetti; animation-timing-function: linear; animation-iteration-count: infinite; animation-duration: calc(60s / var(--speed)); } .confetti i:nth-child(even) { transform: rotate(90deg); } @keyframes confetti { 0% { transform: translateY(-100vh); } 100% { transform: translateY(100vh); } }
Within the code, .confetti i
is used to select every shape and apply animation properties to it.
calc()
is a function used to perform calculations in CSS.
We select .confetti i:nth-child(even)
to rotate every shape whose index is an even number.
Finally, under the @keyframes confetti
, we create an animation to make the shapes move from the top to the bottom of the page.
To make the shapes fall with varying duration and have different colors, we have to pass variables directly to the shapes using HTML and then get rid of :root
entirely:
<div class="confetti-container"> <div class="confetti"> <i style="--bg: red; --speed: 20" class="square"></i> <i style="--bg: green; --speed: 24" class="rectangle"></i> <i style="--bg: white; --speed: 13" class="hexagram"></i> <i style="--bg: yellow; --speed: 10" class="pentagram"></i> <i style="--bg: purple; --speed: 17" class="dodecagram"></i> <i style="--bg: pink; --speed: 15" class="wavy-line"></i> </div> </div>
Next, we’ll create more of these shapes, add random colors, and give them some speed to generate our confetti:
<div class="confetti-container"> <div class="confetti"> <i style="--speed: 10; --bg: yellow" class="square"></i> <i style="--speed: 18; --bg: white" class="pentagram"></i> <i style="--speed: 29; --bg: green" class="rectangle"></i> <i style="--speed: 17; --bg: blue" class="hexagram"></i> <i style="--speed: 33; --bg: red" class="pentagram"></i> <i style="--speed: 26; --bg: yellow" class="dodecagram"></i> <i style="--speed: 24; --bg: pink" class="wavy-line"> </i> <i style="--speed: 5; --bg: blue" class="wavy-line"></i> <i style="--speed: 40; --bg: white" class="square"></i> <i style="--speed: 17; --bg: green" class="rectangle"></i> <i style="--speed: 25; --bg: white" class="square"></i> <i style="--speed: 18; --bg: green" class="rectangle"></i> <i style="--speed: 15; --bg: yellow" class="wavy-line"> </i> <i style="--speed: 32; --bg: yellow" class="pentagram"></i> <i style="--speed: 25; --bg: white" class="square"></i> <i style="--speed: 18; --bg: green" class="rectangle"></i> <i style="--speed: 37; --bg: yellow" class="dodecagram"></i> <i style="--speed: 23; --bg: pink" class="wavy-line"></i> <i style="--speed: 37; --bg: red" class="dodecagram"></i> <i style="--speed: 37; --bg: pink" class="wavy-line"></i> <i style="--speed: 36; --bg: white" class="hexagram"></i> <i style="--speed: 32; --bg: green" class="wavy-line"></i> <i style="--speed: 32; --bg: yellow" class="pentagram"></i> <i style="--speed: 29; --bg: white" class="square"></i> <i style="--speed: 18; --bg: green" class="rectangle"></i> <i style="--speed: 37; --bg: red" class="dodecagram"></i> <i style="--speed: 23; --bg: pink" class="wavy-line"> </i> <i style="--speed: 30; --bg: pink" class="rectangle"></i> <i style="--speed: 30; --bg: red" class="square"></i> <i style="--speed: 18; --bg: red" class="pentagram"></i> <i style="--speed: 19; --bg: green" class="rectangle"></i> <i style="--speed: 16; --bg: blue" class="hexagram"></i> <i style="--speed: 23; --bg: red" class="pentagram"></i> <i style="--speed: 34; --bg: yellow" class="dodecagram"></i> <i style="--speed: 39; --bg: pink" class="wavy-line"></i> <i style="--speed: 40; --bg: purple" class="square"></i> <i style="--speed: 21; --bg: green" class="rectangle"></i> <i style="--speed: 14; --bg: white" class="square"></i> <i style="--speed: 38; --bg: green" class="rectangle"></i> <i style="--speed: 19; --bg: red" class="dodecagram"></i> <i style="--speed: 29; --bg: pink" class="wavy-line"> </i> <i style="--speed: 21; --bg: white" class="hexagram"></i> <i style="--speed: 17; --bg: purple" class="wavy-line"></i> <i style="--speed: 32; --bg: yellow" class="pentagram"></i> <i style="--speed: 23; --bg: white" class="square"></i> <i style="--speed: 18; --bg: green" class="rectangle"></i> <i style="--speed: 37; --bg: red" class="dodecagram"></i> <i style="--speed: 48; --bg: pink" class="wavy-line"> </i> <i style="--speed: 38; --bg: pink" class="rectangle"></i> <i style="--speed: 13; --bg: red" class="pentagram"></i> <i style="--speed: 49; --bg: yellow" class="dodecagram"></i> <i style="--speed: 19; --bg: cyan" class="wavy-line"></i> <i style="--speed: 15; --bg: steelblue" class="square"></i> <i style="--speed: 10; --bg: yellow" class="square"></i> <i style="--speed: 18; --bg: white" class="pentagram"></i> <i style="--speed: 29; --bg: green" class="rectangle"></i> <i style="--speed: 17; --bg: blue" class="hexagram"></i> <i style="--speed: 33; --bg: red" class="pentagram"></i> <i style="--speed: 26; --bg: yellow" class="dodecagram"></i> <i style="--speed: 24; --bg: pink" class="wavy-line"> </i> <i style="--speed: 5; --bg: white" class="wavy-line"></i> <i style="--speed: 40; --bg: purple" class="square"></i> <i style="--speed: 17; --bg: green" class="rectangle"></i> <i style="--speed: 25; --bg: white" class="square"></i> <i style="--speed: 18; --bg: green" class="rectangle"></i> <i style="--speed: 15; --bg: cyan" class="wavy-line"> </i> <i style="--speed: 32; --bg: yellow" class="pentagram"></i> <i style="--speed: 45; --bg: white" class="square"></i> <i style="--speed: 18; --bg: green" class="rectangle"></i> <i style="--speed: 37; --bg: red" class="dodecagram"></i> <i style="--speed: 23; --bg: pink" class="wavy-line"> </i> <i style="--speed: 37; --bg: red" class="dodecagram"></i> <i style="--speed: 37; --bg: pink" class="wavy-line"> </i> <i style="--speed: 26; --bg: white" class="hexagram"></i> <i style="--speed: 32; --bg: cyan" class="wavy-line"></i> <i style="--speed: 32; --bg: yellow" class="pentagram"></i> <i style="--speed: 45; --bg: white" class="square"></i> <i style="--speed: 18; --bg: green" class="rectangle"></i> <i style="--speed: 37; --bg: red" class="dodecagram"></i> <i style="--speed: 23; --bg: pink" class="wavy-line"> </i> <i style="--speed: 50; --bg: pink" class="rectangle"></i> <i style="--speed: 30; --bg: red" class="square"></i> <i style="--speed: 18; --bg: red" class="pentagram"></i> <i style="--speed: 19; --bg: green" class="rectangle"></i> <i style="--speed: 16; --bg: blue" class="hexagram"></i> <i style="--speed: 23; --bg: red" class="pentagram"></i> <i style="--speed: 33; --bg: yellow" class="dodecagram"></i> <i style="--speed: 39; --bg: white" class="wavy-line"></i> <i style="--speed: 40; --bg: orange" class="square"></i> <i style="--speed: 21; --bg: green" class="rectangle"></i> <i style="--speed: 14; --bg: white" class="square"></i> <i style="--speed: 38; --bg: green" class="rectangle"></i> <i style="--speed: 19; --bg: red" class="dodecagram"></i> <i style="--speed: 29; --bg: pink" class="wavy-line"> </i> <i style="--speed: 34; --bg: white" class="hexagram"></i> <i style="--speed: 17; --bg: indigo" class="wavy-line"></i> <i style="--speed: 32; --bg: yellow" class="pentagram"></i> <i style="--speed: 23; --bg: white" class="square"></i> <i style="--speed: 18; --bg: green" class="rectangle"></i> <i style="--speed: 37; --bg: red" class="dodecagram"></i> <i style="--speed: 48; --bg: pink" class="wavy-line"> </i> <i style="--speed: 38; --bg: pink" class="rectangle"></i> <i style="--speed: 13; --bg: red" class="pentagram"></i> <i style="--speed: 49; --bg: yellow" class="dodecagram"></i> <i style="--speed: 19; --bg: purple" class="wavy-line"></i> <i style="--speed: 15; --bg: cyan" class="square"></i> </div> </div>
You can see the final result of our CSS confetti effect in the CodePen below:
See the Pen
CSS Confetti by Onuorah Bonaventure Chukwudi (@bonarhyme)
on CodePen.
We can also include an option for the user to pause the confetti. Add the following style so that we can stop the animation when we click the checkbox:
input:checked + .confetti-container i { /* display: none; */ animation-play-state: paused; }
You can also specify the dimension of the confetti using this style:
.confetti { position: fixed; left: 0; right: 0; display: flex; width: 600px; height: 600px; overflow: hidden; }
N.B., Adding a display of none
removes the confetti from the screen.
The complete code with these bonus styles can be viewed, edited, and forked on CodePen and GitHub:
See the Pen
CSS Confetti with bonus style by Onuorah Bonaventure Chukwudi (@bonarhyme)
on CodePen.
Although it may have seemed daunting, we were able to create a cool confetti effect with CSS! This is all to show that CSS shouldn’t look scary and that you can tap into its superpowers to create amazing animations and layouts.
Thank you for reading through. I hope you enjoyed this article, and be sure to leave a comment if you have any questions. Happy coding!
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowCompare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
One Reply to "How to create a confetti effect in CSS"
Nice, I am going to practice and implement this. Very cool css design and a nice read. Keep on the good work.