Update (March 9, 2012): I have updated this document to include styling information for Internet Explorer 10.

<progress>

progress

The HTML: Simple

As a web application developer,especially when it can take a long time. They can be(like the one in Gmail does when it shows the user how long it is going to take for it to load and initialize),(like some shopping cart applications have to show the user how many pages it will take to check out an order). I used to create progress bars using <div> tags, CSS and a litle bit of math , but now I like to do it the HTML5 way using thetag. This article will discussin all operating systems and browsers and how to, even in browsers that don’t officially support the it. It will also discuss some interestingamd show some

The HTML for a Progress bar is dead simple:

<progress max="100" value="60"> <strong>Progress: 60% done.</strong> </progress>

Progress: 60% done.

Note that the HTML inside the <progress> tag is the fallback for browsers that do not support it. That, unfortunately, includes all versions of IE and Safari so far, as well older versions of Firefox (5.x and lower) and Opera (10.x and lower). Although the fallback is acceptable, we can go a step further and use Lea Verou’s excellent <progress> tag polyfill, which adds pretty much full-support for all of these browsers except for Safari 5 and lower (so you should always put in the fallback HTML just to be on the safe side). Let’s take a look at these screenshots to see what how <progress> looks across the browserverse:

Windows 7 Windows XP Mac OS X Ubuntu Linux Firefox Chrome IE7-9 (polyfill) N/A IE10 N/A Safari 5.1+ (polyfill) N/A Opera

Note that:

Firefox and Chrome will render the progress bar the same way that the host operating system would … except for Chrome for Linux, which uses it’s own custom style (thanks to Mounir Lamouri for correcting me on this exception).

The color of the Opera progress value is always green (more on this later).

The browsers that use the polyfill all render the progress bar with a nice bluish gradient effect

A progress bar can also have an “indeterminate” state, which happens when there is no value attribute.

<progress max="100"> <strong>Progress: 60% done.</strong> </progress>

Progress: 60% done.

This effect is used to show that the state of progress is currently unknown (e.g. how long it will take for a web server to initiate the download of a file if is generating it on the fly). How this looks varies from browser to browser as well.

Windows 7 Windows XP Mac OS X Ubuntu Linux Firefox Chrome IE7-9 (polyfill) N/A IE10 N/A Safari 5.1+ (polyfill) N/A Opera

Note that:

Opera is the only browser that doesn’t distinguish between a progress bar with an indeterminate state and one with a value of zero.

All of the other browsers (including the ones that use the polyfill) animate the indeterminate states. (I have opted to not show all the animations here to avoid readers getting seizures … I hear that would be a bad thing).

One changes the value of the progress bar by changing its DOM node’s .value property. Easy peasy.

But I Want To Style Them My Way!

If you are particular in how you want your <progress> tags to look, the good news is that you can pretty much style them any way you want. You must, however, be aware about the browser quirks that can trip you up … and it isn’t all IE’s fault this time! Follow this three-to-four-step process, and you’ll be styling progress bars in your sleep in no time:

Step 1: Turn off default styling

The first step is to turn off the default styling in all browsers:

progress, /* All HTML5 progress enabled browsers */ progress[role] /* polyfill */ { /* Turns off styling - not usually needed, but good to know. */ appearance: none; -moz-appearance: none; -webkit-appearance: none; /* gets rid of default border in Firefox and Opera. */ border: none; /* Needs to be in here for Safari polyfill so background images work as expected. */ background-size: auto; /* Dimensions */ width: 400px; height: 60px; } /* Polyfill */ progress[role]:after { background-image: none; /* removes default background from polyfill */ } /* Ensure fallback text doesn't appear in polyfill */ progress[role] strong { display: none; }

Progress: 60% done.

Simple stuff: remove the border and add a specific width and height. I added the second rule to remove the background image inserted by the polyfill’s stylesheet, but if you wanted, you can modify the polyfill’s stylesheet directly (or leave it out completely if you elect not to use the polyfill). The final rule is to ensure the polyfill doesn’t display the fallback content — it assumes that is always wrapped in a <strong> tag, so this may be something you should keep in mind when setting the default content (if you don’t like using a <strong> tag as a wrapper for your fallback content, use whatever tag you like).

Note that the appearance property (and its vendor-specific brethren) are there to turn off the default operating-system styling on the progress bar — it doesn’t seem like it is really necessary, but I put it here for reference in case it becomes mandatory in the future.

Step 2: The Progress Bar Background.

Now let’s change the background color of the progress bar to a light red.

progress, /* Firefox */ progress[role][aria-valuenow] { /* Polyfill */ background: #ffeeee !important; /* !important is needed by the polyfill */ } /* Chrome */ progress::-webkit-progress-bar { background: #ffeeee; }

Notice that with Firefox and the polyfilled browsers, all you need to do is change the background of just the progress tag itself, while in Chrome (and I assume future versions of Safari) it is necessary to use the -webkit-progress-bar pseudo-element. Note that even though the code inside these rules are the same, you cannot put all of these selectors in one rule: doing so breaks Firefox and Opera (so much for degrading gracefully).

Step 3: The Progress Bar Value

Now let’s change the color of progress bar value to black. The CSS is a wee bit longer than it really should be:

/* IE10 */ progress { color: black; } /* Firefox */ progress::-moz-progress-bar { background: black; } /* Chrome */ progress::-webkit-progress-value { background: black; } /* Polyfill */ progress[aria-valuenow]:before { background: black; }

Yes, three rules to rule them all! Yes, four rules are needed now if you include IE 10! Again, putting them all together in one selector breaks every browser on the planet (including the polyfilled ones), so we have to write three separate rules with the same CSS properties in them! <sarcasm>Yaaayyy!!!!</sarcasm>

Note that there is no way that I know of to style the progress bar value in Opera 11.52 and lower. It just stays the same green no matter what you do. :-( If anyone is reading this and knows otherwise, I would be indebted to you to let me know how. Note also that as of this writing, the preview release of Internet Explorer 10 does not allow styling of the progress bar value with an image, only a color using the color attribute, so some of these examples do not look as intended in that browser)

Step 4: The Indeterminate Value

This part is optional, and I would only put these rules in if I know I’ll need a style for the indeterminate value (not all applications need it):

/* Firefox */ progress:not([value])::-moz-progress-bar { background-image: url(../images/indeter.gif); } /* Chrome */ progress:not([value])::-webkit-progress-bar { background-image: url(../images/indeter.gif); } /* Polyfill - IE */ progress[role]{ background-image: url(../images/indeter.gif) !important; } /* Polyfill - Safari */ progress:not([value]) { background-image: url(../images/indeter.gif) !important; background-size: auto; /* Needs to be in here for Safari */ }

It even works in Opera! Note that the background-size must be set to auto in order to override the default style in the polyfill. :-)

See the above CSS in action in a “clean room” page

That’s Too Basic! I Want Fancy-Pants™ Progress Bars

So, now that you know the basics, let’s take a look at some more complicated and interesting progress bars:

Two Image Effect

This progress bar uses two versions of the same image (one grey-scale, one color) to differentiate between the progress bar background and value:

See the above example in action in a “clean room” page

Unfortunately, this example doesn’t work in Opera and IE10, since at this time one cannot style the progress bar value with an image in those browsers.

Gradients

Note that not only can you use background-color s and -image s, but also use the variety of gradients that are available for developers today in supported browsers (this does not include IE9 and lower). To prove this, I took Chris Croyer beautiful <div> style progress bars from his blog post on CSS3 based progress bars and HTML5-ified™ them here:

Unfortunately, due to CSS gradients being implemented by the browser vendors using vendor-specific prefixes, the CSS tends to be a wee long. Here is the CSS of the first example (scroll the code to see the whole lot of it):

/* * Gradient Shadow */ /* All HTML5 progress enabled browsers */ progress.example3 { /* Turns off styling - not usually needed, but good to know. */ appearance: none; -moz-appearance: none; -webkit-appearance: none; /* gets rid of default border in Firefox and Opera. */ border: solid #cccccc 5px; border-radius: 10px; /* Dimensions */ width: 238px; height: 45px; } /* Polyfill */ progress.example3[role]:after { background-image: none; /* removes default background from polyfill */ } /* * Background of the progress bar background */ /* Firefox and Polyfill */ progress.example3 { background: #cccccc !important; /* !important only needed in polyfill */ } /* Chrome */ progress.example3::-webkit-progress-bar { background: #cccccc; } /* * Background of the progress bar value */ /* Firefox */ progress.example3::-moz-progress-bar { border-radius: 5px; background-image: -moz-linear-gradient( center bottom, rgb(43,194,83) 37%, rgb(84,240,84) 69% ); } /* Chrome */ progress.example3::-webkit-progress-value { border-radius: 5px; background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0, rgb(43,194,83)), color-stop(1, rgb(84,240,84)) ); background-image: -webkit-linear-gradient( center bottom, rgb(43,194,83) 37%, rgb(84,240,84) 69% ); } /* Polyfill */ progress.example3[aria-valuenow]:before { border-radius: 5px; background-image: -moz-linear-gradient( center bottom, rgb(43,194,83) 37%, rgb(84,240,84) 69% ); background-image: -ms-linear-gradient( center bottom, rgb(43,194,83) 37%, rgb(84,240,84) 69% ); background-image: -o-linear-gradient( center bottom, rgb(43,194,83) 37%, rgb(84,240,84) 69% ); }

This example doesn’t work in any version of IE (since that browser can only change the color, not the background image, of a progress bar value) or Opera (since it can’t style the progress bar at all). Also, note that I did not use the Gradient filter to polyfill CSS3 gradients in IE6-9. This is because Visual Filters don’t work in CSS3 pseudo-elements like :before or :after . Oh well.

See the above CSS in action in a “clean room” page

Monkeys!

What blog post about HTML5 progress tags would be complete without monkeys? These simians appear in all browser except for IE8 and lower (as explained below).

Apologies to the great Banksy — it’s not his monkey but one grabbed from this Animated GIF site and converted into a CSS sprite using André Gil’s super-cool Gif2TileSet tool. I took this sprite and animated the monkey using blitting whenever the progress bar changes values (thanks to my friend and colleague Noel Tibbles for turning me on to this technique).

Note the HTML has an extra <div> tag so the monkey has a place to live:

<progress class="monkey" min="0" max="100" value="60"></progress> <div class="after"></div>

I wish that I could have used :after (or ::after ) rules instead, but these pseudo-elements don’t work with the progress tags in any browser that doesn’t use the polyfill. And no, :before doesn’t work either. I have no idea why it doesn’t work, but it’s a shame — using them would be perfect to get rid of the extra markup.

The CSS that makes the monkey animate when the progress bar changes values is here:

progress.monkey[value="0"] + .after{ background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif'); } progress.monkey[value^="1"] + .after { background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif') 0 -77px ; } progress.monkey[value^="2"] + .after { background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif') 0 -154px ; } progress.monkey[value^="3"] + .after, progress.monkey[value="100"] + .after { background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif') 0 -231px !important ; } progress.monkey[value^="4"] + .after { background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif') 0 -308px ; } progress.monkey[value^="5"] + .after { background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif') 0 -385px ; } progress.monkey[value^="6"] + .after { background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif') 0 -462px ; } progress.monkey[value^="7"] + .after { background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif') 0 -539px ; } progress.monkey[value^="8"] + .after { background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif') 0 -616px ; } progress.monkey[value^="9"] + .after { background: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif') 0 -693px ; }

Each of these rules are applied when the first digit changes in the progress bar, which is done using the ^= attribute rules. This works because the progress bar goes from 0 – 100 and the progress bar increments by 10. They monkeys don’t appear in IE8 and under because of it’s lack of support of the ^= attribute selector (but it works well in IE9).

Note that this would be much easier if CSS allowed us to combine the CSS3 calc() and attr() attributes together like Lea Verou dreams about in one of her blog posts:

/* * Don't try this - it doesn't work in any browser, but it would be nice if it did. */ progress.monkey::after { background-image: url('/blog/wp-content/uploads/2011/12/monkeyBlit.gif'); background-position-x: 0; background-position-y: calc(-77 * attr(value), 'px'); }

Hopefully this will come to pass in the future.

See the above CSS in action in a “clean room” page

Speedometer

My last example is radically different than the others. How about we apply the speedometer metephor to the progress bar with some fancy-pants CSS3? This example in all browsers except IE8 and lower (due to lack of support for native CSS3 transform )

The CSS is similar to the monkey example in that I add an extra <div> after the progress tag, except that it has an image of a pointer inside of it.

<div id="progressContainer"> <progress id="rot" class="example_r" min="0" max="100" value="60"></progress> <div data-arrow-for="rot" class="arrow"><img src="/blog/wp-content/uploads/2012/01/hand.png" /></div> </div>

I wrapped both these tags inside a relatively positioned container <div> . This is so I could absolutely position both the progress bar and the arrow in order for them to line up properly. I make the progress bar into a semi-circle by using border-radius and part of a photo from Flickr user ‘listener42’ …

progress.example_r { /* gets rid of default border in Firefox and Opera. */ border: solid 1px black; display: inline-block; /* Produces the semi-circle */ border-radius: 238px 238px 0 0; /* Dimensions */ width: 238px; height: 126px; padding: 0; /* IE needs this to hide the native progress bar value */ color: transparent; }

… and make the arrow rotate as the progress bar increments by using CSS transforms:

progress.example_r[value="0"] + .arrow { -moz-transform: rotate(270deg); -webkit-transform: rotate(270deg); -o-transform: rotate(270deg); -ms-transform: rotate(270deg); } progress.example_r[value^="1"]:not([value="1"]):not([value="100"]) + .arrow { -moz-transform: rotate(288deg); -webkit-transform: rotate(288deg); -o-transform: rotate(288deg); -ms-transform: rotate(288deg); } progress.example_r[value^="2"]:not([value="2"]) + .arrow { -moz-transform: rotate(306deg); -webkit-transform: rotate(306deg); -o-transform: rotate(306deg); -ms-transform: rotate(306deg); } progress.example_r[value^="3"]:not([value="3"]) + .arrow { -moz-transform: rotate(324deg); -webkit-transform: rotate(324deg); -o-transform: rotate(324deg); -ms-transform: rotate(324deg); } progress.example_r[value^="4"]:not([value="4"]) + .arrow { -moz-transform: rotate(342deg); -webkit-transform: rotate(342deg); -o-transform: rotate(342deg); -ms-transform: rotate(342deg); } progress.example_r[value^="5"]:not([value="5"]) + .arrow { -moz-transform: rotate(360deg); -webkit-transform: rotate(360deg); -o-transform: rotate(360deg); -ms-transform: rotate(360deg); } progress.example_r[value^="6"]:not([value="6"]) + .arrow { -moz-transform: rotate(378deg); -webkit-transform: rotate(378deg); -o-transform: rotate(378deg); -ms-transform: rotate(378deg); } progress.example_r[value^="7"]:not([value="7"]) + .arrow { -moz-transform: rotate(396deg); -webkit-transform: rotate(396deg); -o-transform: rotate(396deg); -ms-transform: rotate(396deg); } progress.example_r[value^="8"]:not([value="8"]) + .arrow { -moz-transform: rotate(414deg); -webkit-transform: rotate(414deg); -o-transform: rotate(414deg); -ms-transform: rotate(414deg); } progress.example_r[value^="9"]:not([value="9"]) + .arrow { -moz-transform: rotate(432deg); -webkit-transform: rotate(432deg); -o-transform: rotate(432deg); -ms-transform: rotate(432deg); } progress.example_r[value="100"] + .arrow { -moz-transform: rotate(450deg); -webkit-transform: rotate(450deg); -o-transform: rotate(450deg); -ms-transform: rotate(450deg); }

Again, the CSS would be much smaller in size if I could use calc() and attr() together, but again, oh well. Furthermore, that this example doesn’t work in Opera very well because we cannot turn of the green in the progress bar value. Although we can hide this bar in IE10 by setting the progress bar’s color to transparent a thin line can be seen where the end of the progresss bar used to be. Ugh… :-(

See the above CSS in action in a “clean room” page

Summary of Gotchas

As mentioned before, there are a few annoyances I have found with they way the browsers have implemented HTML5 progress bars:

You cannot use :before / ::before or :after / ::after pseudo-elements on the progress element. Why this is not allowed is unclear to me, and I hope this is allowed in the future. Safari 5.0 and lower cannot use the polyfill, so you should always use the fallback HTML inside the <progress> tag. It seems like it is impossible to change Opera’s progress bar value style to anything besides green. While you can change the progress bar value color in IE10, as far as I know it is impossible to apply a background image to it. There is a small bug in the polyfill when applying borders to the progress bar. I have a fix that has been submitted as a pull request and I assume being reviewed, but in the meantime, you can get my forked version of the polyfill (with the bug fix) on GitHub.

Help Me Keep This Page Up-To-Date!