I made some progress bars. They look like as below:

They use no image, just CSS3 fancies. Like a good little designer always does, they fall back to totally acceptable experience. Here’s what they look like in Opera 11 and are supported by some of the CSS3 but not all.

As you can imagine, in browsers that support no CSS3 at all will be shown similar to the above, only even more simplified.

HTML Base

The bar itself will be a

with a class of meter. Within that is a , acting as the “filled” area of the progress bar. This is set with an inline style. It’s the markup which will show how far to fill a progress bar, so this is a case where inline styles make perfect sense. The CSS alternative will create classes like “fill-10-percent”, “fill-one-third” or stuff like that, which is heavier and less flexible.

The basic:

HTML

div class=meter> span style=width: 25%>span> div>

Start of CSS

The div wrapper is the track of the progress bar. We won’t set a width, so it will stretch as wide as it’s parent as a block level element does. You could though. Height is also arbitrary. It’s set at 20px here but could be different. We’ll round the corners in as many browsers as we can and set an inset shadow to give it a hair of depth.

CSS

.meter {
     height: 20px; /* Can be anything */
     position: relative;
     background: #555;
     -moz-border-radius: 25px;
     -webkit-border-radius: 25px;
     border-radius: 25px;
     padding: 10px;
     box-shadow: inset 0 -1px 1px rgba(255,255,255,0.3);
}

Then span inside will be the fill in part of the progress bar. We’ll make it display as a block with 100% height, so it stretches to fit whatever room it has. We’ll then use a bunch of CSS3 to give it gradient look and round it’s corners.

CSS

.meter > span {
   display: block;
   height: 100%;
   border-top-right-radius: 8px;
   border-bottom-right-radius: 8px;
   border-top-left-radius: 20px;
   border-bottom-left-radius: 20px;
   background-color: rgb(43,194,83);
   background-image: linear-gradient(
   center bottom,
   rgb(43,194,83) 37%,
   rgb(84,240,84) 69%
);
   box-shadow:
      inset 0 2px 9px rgba(255,255,255,0.3),
      inset 0 -2px 6px rgba(0,0,0,0.4);
   position: relative;
   overflow: hidden;
}

Thems the basics.

Other Colors

Let’s make it as easy as possible to change the color. Just add a class name of “orange” or “red” to the div wrapper and the color will override.

CSS

.orange > span {
   background-color: #f1a165;
   background-image: linear-gradient(to bottom, #f1a165, #f36d0a);
}

.red > span {
   background-color: #f0a3a3;
   background-image: linear-gradient(to bottom, #f0a3a3, #f42323);
}

Candystriping

We can get a cool striped effect by adding another element on top of that span and laying a repeated CSS3 gradient over it. Semantically this is best achieved with a pseudo element, so let’s do it that way. We’re going to absolutely position it over the exact area of the span (which already has relative position) and then round the corners the same so the stripes don’t stick out weird.

CSS

.meter > span:after {
   content: “”;
   position: absolute;
   top: 0; left: 0; bottom: 0; right: 0;
   background-image: linear-gradient(
      -45deg,
     rgba(255, 255, 255, .2) 25%,
     transparent 25%,
     transparent 50%,
     rgba(255, 255, 255, .2) 50%,
     rgba(255, 255, 255, .2) 75%,
     transparent 75%,
     transparent
);
   z-index: 1;
   background-size: 50px 50px;
   animation: move 2s linear infinite;
   border-top-right-radius: 8px;
   border-bottom-right-radius: 8px;
   border-top-left-radius: 20px;
   border-bottom-left-radius: 20px;
   overflow: hidden;
}

Animating Candystripes

Only Firefox 4 can animate pseudo elements, and only WebKit can do keyframe animations. So unfortunately, we’re between a rock and a hardplace in terms of animating those stripes. If we’re set on it, let’s add an additional span and then WebKit animate that.

HTML

class=“meter animate”>
    style=“width: 50%”>

The span will be exactly the same as the pseudo element, so we’ll just use the same values…

CSS

.meter > span:after, .animate > span > span {

… and avoid doubling up:

.animate > span:after { display: none; }

We’ll move the background position as far as the size of it:

CSS

@keyframes move {
0% {
   background-position: 0 0;
}
100% {
   background-position: 50px 50px;
}
}

And call that animation:

.meter > span:after, .animate > span > span {
   animation: move 2s linear infinite;
}

Might as well leave the animation tied to the pseudo element too, so as soon as WebKit starts supporting that, it will work.

Animating the Filled Width

Unfortunately, you can’t animate to an auto or natural width, which might let us animate from a forced zero to the inline style.

CSS

@keyframes expandWidth { 0% { width: 0; } 100% { width: auto; } }

I’ve submitted it to major browsers bug trackers just to push it a long a little, but for now, unsupported. Instead, let’s do it with jQuery. Measure the original width, force it down to zero, then animate back up:

jQuery

$(“.meter > span”).each(function() {
   $(this)
   .data(“origWidth”, $(this).width())
   .width(0)
   .animate({
   width: $(this).data(“origWidth”) // or + “%” if fluid
   }, 1200);
});

And done!