DEV Community

Cover image for Let's make and eat those CSS3 progress bars. 🍭
Vaibhav Khulbe
Vaibhav Khulbe

Posted on • Updated on

Let's make and eat those CSS3 progress bars. 🍭

Are you the one who still eats candies? Striped ones? 🍭 Well, I used to love them when I was a kid. So what I love now? I love CSS. 🀩

Let's do it. We'll transform a 'sweet' striped candy bar to a progress bar. Because...well, to be honest, the default HTML <progress> is bad. I mean look at this...

Progress bar

We can sincerely convert this into a much 'sweeter' one and that too without the need of <progress>. Sounds exciting? Let's dive in!

Candy GIF

Time to give back candies its lost glory πŸ₯Ί

Finish off the HTML first πŸ€ͺ

Because...well, you need something to style on? What we want to achieve is the following loading/spinning candy bar:

loadingcandyfinished GIF

If you wear your frontend goggles and observe, you see there are two layers or elements we need to do this. First off is the bar holder element and the one above it is the actual candy bar with red colour. So, this is what we start with:

Enter fullscreen mode Exit fullscreen mode

The div is our holder upon which we will have a span to make it an inline container. Here, see how it looks in the Chrome Dev Tools:


The skin colored element is our div on which the blue colored span is sitting.

Let's make it look like a candy 🍭

Here comes the interesting stuff. First, give the div a class of loading-bar and in CSS this is what we need to style it:

.loading-bar {
  position: relative;
  margin: 0 auto;
  height: 50px;
  width: 30%;
  border-radius: 50px;
Enter fullscreen mode Exit fullscreen mode

Now the relative positioning is optional here as we are not setting values for the top, left, bottom or right properties to position it explicitly. We just center this to the document body by putting a margin of top and bottom to be 0 and left/right to be auto. Setting a default width and height is necessary because without these we won't be able to see the div. These could be any value depending upon how big you want the bar to be. A nice, round border is also a good take to give it a shape of a loading bar.

You won't be able to see anything right now because technically the color of that div and the body element is both white by default. Try to add background-color: orangered; to the div and you'll now get your base holder.

Up next, we need to add those funky candy stripes, for that style the span as follows:

span {
  display: block;
  position: relative;
  height: 100%;
  width: 100%;
  border-radius: 50px;
  background-image: linear-gradient(to bottom, #fac4c0, #f60000 60%);
    inset 0 2px 9px  rgba(255,255,255,0.3),
    inset 0 -2px 6px rgba(0,0,0,0.4);
  overflow: hidden;
Enter fullscreen mode Exit fullscreen mode

The block display ensures that it has a block-style element box with an equal amount of space before and after the span. This time we need it to be 100% area of the parent (i.e. div) so we give it the respective value of the width, height and border-radius. Any extra element (if it occurs) is clipped off the span by setting the value of overflow to hidden.

Still, you won't be able to see anything :( We need to add some coloring! We do this by using a linear-gradient which is at a 180Β° angle. The bright red #f60000 color occupies 60% of the total gradient value. And just when you do this you see our loader has a gradient!

Completely optional...

Time to add some depth so that it looks more like a candy. We add two shadow values. The first one adds a white shadow drop to the top and the second is black, at the bottom. The main point is that you need to use the inset so it looks like shadow is coming from one side. These type of shadows are drawn inside its container.

Add stripes! 🌈

We're coming close! A candy with no stripe is a bad-looking candy for me. To do this, we need to understand the ::after pseudo element in CSS. According to the Mozilla Developer Network (MDN) docs:

In CSS, ::after creates a pseudo-element that is the last child of the selected element. It is often used to add cosmetic content to an element with the content property. It is inline by default.

How it will help us? Well, we create our stripe pseudo-element with ::after!

span:after {
  content: "";
  position: absolute;
  top: 0px; left: 0; bottom: 0; right: 0;
  background-image: linear-gradient(
    rgba(255, 255, 255, .2) 25%, 
    transparent 25%, 
    transparent 50%, 
    rgba(255, 255, 255, .2) 50%, 
    rgba(255, 255, 255, .2) 75%, 
    transparent 75%, 
  z-index: 1;
  background-size: 50px 50px;
  border-top-right-radius: 8px;
  border-bottom-right-radius: 8px;
  border-top-left-radius: 20px;
  border-bottom-left-radius: 20px;
  overflow: hidden;
Enter fullscreen mode Exit fullscreen mode

Every pseudo-element has to have a content property. Whatever is the value of content, it will replace that element with the newly generated value. If you add content: "🍬";, whatever your div was showing previously will now be replaced by "🍬". Sweet? But we don't want any content inside the newly created ::after element. It will show up inside the span and is totally useless...until we add nothing! That's why we just use ' ' (blank).

Stripe magic starts! We use background-image property to add a big gradient. Let's decode it one at a time:

  • -45deg: This is the angle at which our gradient will be tilted.
  • rgba(255, 255, 255, .2) 25%: A white (The value 255 means white in the rgb format) color with .2 as its opacity. 25% is the area it takes in the entire element.
  • transparent 25%: A transparent value of color with the same 25% area of the total.

There are three main values we focus on. Nothing much will change if you use just these. Now, look at the stripe pattern closely...

Progress Candy Still

...we can see that if there are multiple color-stops with the same position, they produce a transition from the first to the last. So what comes out is, the color suddenly changes at that position rather than smoothly transitioning. All this is possible because of the CSS3's background-image property which supports color stops as specified in W3C's draft.

This is how after repeating it several times all over the span (don't forget to use absolute positioning this time), we get a striped pattern perfect for our candy!

The default background-size of half of the entire element are i.e. 50% on both width and height seems reasonable. Also, we need to make these stripes inside the container so we use the overflow and the specific border properties as our parent div on all four directions.

Make it animate! 🎬

The real loading starts now. Let's select the newly created ::after element, create an animate class and we then select the span under it. Define the animation with 1s duration, running infinitely.

.loading-bar > span:after, .animate > span > span { 
  animation: load 1s infinite;
Enter fullscreen mode Exit fullscreen mode

Now it's pretty straightforward. What we want to animate is the position of the stripes. The initial div stays locked in its position, stripes move on top indicating as if something is loading in the background.

@keyframes load {
  0% {
    background-position: 0 0;
  100% {
    background-position: 50px 50px;
Enter fullscreen mode Exit fullscreen mode

We start from zero to the 50px of width and height respectively. And there it is! How sweet that looks. 🀀

Here's the CodePen to achieve this candy loader:

So, who's ready to eat that candy? πŸ‘€

Candy eating

Where to next? πŸ€”

Fiddle around! We just made a loader this time, how about making an actual candy 'progress' bar? This time, the stripes move over the holder and move from left to right as if it's loading. This is what I'm talking about:

Candy loader GIF

If you're stuck making this, no worries, see the CodePen example I made.

Thanks for reading, I appreciate it! Have a good day. (βœΏβ—•β€Ώβ—•βœΏ)

Have you tried using Microsoft Docs yet?

We're not saying it'll change the way you program but at the same time we're not saying it won't. πŸ˜‰

Check it out:

Image source: #Programming

β€” Microsoft Developer UK (@msdevUK) June 17, 2020

πŸ“« Subscribe to my weekly developer newsletter πŸ“«

PS: From this year, I've decided to write here on DEV Community. Previously, I wrote on Medium. If anyone wants to take a look at my articles, here's my Medium profile.

Top comments (5)

shivarajnaidu profile image

Nice article .. can you write about circular progress bars. ?

vaibhavkhulbe profile image
Vaibhav Khulbe • Edited

Thanks! Circular candy progress bars --- up next. 😎

vaibhavkhulbe profile image
Vaibhav Khulbe
bernardbaker profile image
Bernard Baker

Nice 🀸

vaibhavkhulbe profile image
Vaibhav Khulbe