DEV Community

Cover image for How to create a confetti effect in CSS
Matt Angelosanto for LogRocket

Posted on

How to create a confetti effect in CSS

Written by Onuorah Bonaventure✏️

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.

Setting up our files

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>
Enter fullscreen mode Exit fullscreen mode

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.

Creating different styles of confetti with CSS

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 */
}
Enter fullscreen mode Exit fullscreen mode

The label and input come next:

label {
  color: white;
  font-size: 1.5rem;
}
input {
  width: 40px;
  height: 40px;
  cursor: pointer;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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.

Creating the different confetti shapes

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!

Creating a square

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);
}
Enter fullscreen mode Exit fullscreen mode

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.

Create a rectangle

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);
}
Enter fullscreen mode Exit fullscreen mode

Creating a hexagram

.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;
}
Enter fullscreen mode Exit fullscreen mode

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.

Creating a pentagram

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: "";
}
Enter fullscreen mode Exit fullscreen mode

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.

Creating a dodecagram

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;
}
Enter fullscreen mode Exit fullscreen mode

.confetti .dodecagram generates a square, but confetti .dodecagram:before and .confetti .dodecagram:after generate two rotated squares.

Creating a wavy line with CSS

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%
  );
}
Enter fullscreen mode Exit fullscreen mode

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.

Animate shapes with a waterfall effect

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

Randomizing shapes, animation, duration, and color

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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.

Bonus styles

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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.

Conclusion

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!


How to create a confetti effect in CSS

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 sign-up

LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app or site. 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.

Top comments (0)