CSS Bar Chart Using HTML5 Progress

I published a post about how to make a responsive CSS bar chart a little while back. Since then, several people have asked how to do the same thing, but a horizontal version. That’s what we’re going to cover in this post.

I also saw that Brad Frost made a pretty nifty bar chart on his site, so I figured we could use that as the model for our example. He uses the HTML5 <progress> element to build his, which feels appropriate when dealing with a horizontal layout. Browser support isn’t 100% with this feature, so use this wisely and provide good fallbacks, where possible.

The biggest difference with this bar chart is that it will be completely done in CSS. I used a little Javascript in the vertical version and Brad used some in his to get the animation effect, but I wanted to keep this one pretty straightforward, so we’ll be using CSS for the animations, even though the support is limited.

Here is what we will be creating:

  • Nunchucks

    Progress: 50%
  • Bow Staff

    Progress: 75%
  • Roundhouse Kick

    Progress: 25%

The HTML Setup

{!{code class="language-html"}!}czo2Njg6XCImbHQ7dWwgY2xhc3M9XCJza2lsbC1saXN0XCImZ3Q7DQogIA0KICAmbHQ7bGkgY2xhc3M9XCJza2lsbFwiJmd0Ow0KICAgICZse1smKiZdfXQ7aDMmZ3Q7TnVuY2h1Y2tzJmx0Oy9oMyZndDsNCiAgICAmbHQ7cHJvZ3Jlc3MgY2xhc3M9XCJza2lsbC0xXCIgbWF4PVwiMTAwXCIgdmFse1smKiZdfXVlPVwiNTBcIiZndDsNCiAgICAgIDxzdHJvbmc+U2tpbGwgTGV2ZWw6IDUwJTwvc3Ryb25nPg0KICAgICZsdDsvcHJvZ3Jlc3MmZ3Q7DXtbJiomXX0KICAmbHQ7L2xpJmd0Ow0KICANCiAgJmx0O2xpIGNsYXNzPVwic2tpbGxcIiZndDsNCiAgICAmbHQ7aDMmZ3Q7Qm93IFN0YWZmJmx0Oy97WyYqJl19aDMmZ3Q7DQogICAgJmx0O3Byb2dyZXNzIGNsYXNzPVwic2tpbGwtMlwiIG1heD1cIjEwMFwiIHZhbHVlPVwiNzVcIiZndDsNCiAgICAgIDxzdHtbJiomXX1yb25nPlNraWxsIExldmVsOiA3NSU8L3N0cm9uZz4NCiAgICAmbHQ7L3Byb2dyZXNzJmd0Ow0KICAmbHQ7L2xpJmd0Ow0KICANCiAge1smKiZdfSZsdDtsaSBjbGFzcz1cInNraWxsXCImZ3Q7DQogICAgJmx0O2gzJmd0O1JvdW5kaG91c2UgS2ljayZsdDsvaDMmZ3Q7DQogICAgJmx0O3tbJiomXX1wcm9ncmVzcyBjbGFzcz1cInNraWxsLTNcIiBtYXg9XCIxMDBcIiB2YWx1ZT1cIjI1XCImZ3Q7DQogICAgICA8c3Ryb25nPlNraWxsIExldmVse1smKiZdfTogMjUlPC9zdHJvbmc+DQogICAgJmx0Oy9wcm9ncmVzcyZndDsNCiAgJmx0Oy9saSZndDsNCg0KJmx0Oy91bCZndDtcIjt7WyYqJl19{!{/code}!}

The first thing you’ll notice is that we’re wrapping this in an unordered list <ul> element. I did this because it feels right when displaying a list of items. I’ve given this a “skill-list” class name, but you can use whatever you’d like. For example, if this is a chart outlining your recent projects, you could call it “project-list.” Whatever makes the most sense to you.

That means each line is written using the list item <li> element. I’ve given each of these a “skill” class name and this can also be whatever you’d like.

Inside each list item is our <h3>, which will be the label for the progress bar.

After that is our HTML5 <progress> tag, which will act as the meter itself. Note that the max value is the highest value in the meter (in this example, 100). The value is the number that represents where the progress meter stops. In this example, “25” will be 25% of the max value, 100.

Finally, I’ve included content wrapped in the <strong> tag. This will not actually display in our chart but provides nice context, especially where accessibility is a concern.

Style the Progress Element

Once the HTML is in place, we can start styling. The first thing I would recommend tackling is the <progress> element itself.

By default, <progress> is styled differently, depending on which browser it is viewed on. We can reset that using the appearance property. At time that I am writing this, only Safari and Chrome support this with the -webkit prefix and Firefox with the -moz prefix. I would include the un-prefixed property in there as well for future support.

{!{code class="language-scss"}!}czoxOTM6XCJwcm9ncmVzcywgcHJvZ3Jlc3Nbcm9sZV0gew0KICAtd2Via2l0LWFwcGVhcmFuY2U6IG5vbmU7DQogICAgIC1tb3otYXB7WyYqJl19cGVhcmFuY2U6IG5vbmU7DQogICAgICAgICAgYXBwZWFyYW5jZTogbm9uZTsNCiAgYm9yZGVyOiBub25lOw0KICBiYWNrZ3JvdW5kLXtbJiomXX1zaXplOiBhdXRvOw0KICBoZWlnaHQ6IDEwMHB4Ow0KICB3aWR0aDogMTAwJTsNCn1cIjt7WyYqJl19{!{/code}!}

In addition to appearance, I removed the border, set the background-size and gave it a height of 100px and a width of 100%. Using 100% for the width will allow this to scale for responsive sites.

Style the List Elements

Next, we’re going to style the unordered list and list items. I gave the <ul> a “skill-list” class and <li> a “skill” class, so let’s apply styles to those classes.

{!{code class="language-scss"}!}czo4NDU6XCIvLyBUaGUgdW5vcmRlcmVkIGxpc3QNCi5za2lsbC1saXN0IHsNCiAgbGlzdC1zdHlsZTogbm9uZTsNCiAgbWFyZ2luOiB7WyYqJl19MDsNCiAgcGFkZGluZzogMWVtOw0KfQ0KDQovLyBUaGUgbGlzdCBpdGVtDQouc2tpbGwgew0KICBtYXJnaW4tYm90dG9tOiAxZW07DXtbJiomXX0KICBwb3NpdGlvbjogcmVsYXRpdmU7DQogIGgzIHsNCiAgICBjb2xvcjogI2ZmZjsNCiAgICBmb250LXNpemU6IDJlbTsNCiAgICBme1smKiZdfW9udC1mYW1pbHk6IFwiSGVsdmV0aWNhIE5ldWVcIiwgYXJpYWwsIHNhbnMtc2VyaWY7DQogICAgbGVmdDogMWVtOw0KICAgIGxpbmUtaHtbJiomXX1laWdodDogMTsNCiAgICBwb3NpdGlvbjogYWJzb2x1dGU7DQogICAgdG9wOiAxZW07DQogIH0NCiAgOjotd2Via2l0LXByb2dyZXNze1smKiZdfS12YWx1ZSB7IA0KICAgIC13ZWJraXQtYW5pbWF0aW9uOiBiYXItZmlsbCAyczsNCiAgICB3aWR0aDogMHB4Ow0KICB9DQp9DQoNCi97WyYqJl19LyBUaGUgYmFja2dyb3VuZCBjb2xvcnMNCi5za2lsbC0xOjotd2Via2l0LXByb2dyZXNzLXZhbHVlIHsNCiAgYmFja2dyb3VuZDogI3tbJiomXX1mZjllMmM7DQp9DQoNCi5za2lsbC0xOjotbW96LXByb2dyZXNzLWJhciB7DQogIGJhY2tncm91bmQ6ICNmZjllMmM7DQp9DQoNCi5ze1smKiZdfWtpbGwtMjo6LXdlYmtpdC1wcm9ncmVzcy12YWx1ZSB7DQogIGJhY2tncm91bmQ6ICM0ZWNkYzQ7DQp9DQoNCi5za2lsbC0yOjotbW97WyYqJl19ei1wcm9ncmVzcy1iYXIgew0KICBiYWNrZ3JvdW5kOiAjNGVjZGM0Ow0KfQ0KDQouc2tpbGwtMzo6LXdlYmtpdC1wcm9ncmVzcy12YXtbJiomXX1sdWUgew0KICBiYWNrZ3JvdW5kOiAjZmY2YjZiOw0KfQ0KDQouc2tpbGwtMzo6LW1vei1wcm9ncmVzcy1iYXIgew0KICBiYWNrZ3Jve1smKiZdfXVuZDogI2ZmNmI2YjsNCn1cIjt7WyYqJl19{!{/code}!}

The skill-list class defines the unordered list that everything is contained in, so we’ll start there. I set the list-style to none to get rid of the bullet points that would display next to each list item by default. Then, I set the margin to zero and padding to 1em to so our graph has a little breathing room on the page.

The skill class defines the list items that contain our progress bars. I gave this a little space by adding some margin to the bottom and set the position to relative.

Next, I styled the Heading 3, which acts as the label for each list item. I set the color to white, and gave it an absolute position so it will lay right on top of the progress bar and let us push it around using the top and left properties. If your stylesheet already has default styles for <h3>, then you may need to adjust these accordingly to be consistent with your site.

I also nested the WebKit pseudo-element for progress-value and gave it a width and an animation. Firefox unfortunately does not support on the <progress> element yet, so we’ll have to go without. We haven’t defined that animation in our code yet, so let’s do that next.

Finally, I set the <background-color> for the three different skills. Note that the background is set twice for each class because Firefox uses a different pseudo-element for defining the color bar than Chrome and Safari.

Add the Progress Animation

I decided to use CSS3 keyframes to animate this bar chart. As mentioned, this will only work with Chrome and Safari for the time being. You could use some Javascript chops to accomplish the same thing for better cross-browser support, but I see the animation as a nice-to-have feature that won’t break the user experience and want to use as little Javascript as possible.

{!{code class="language-scss"}!}czoxMTk6XCIgLy8gVGhlIGtleWZyYW1lcw0KQC13ZWJraXQta2V5ZnJhbWVzIGJhci1maWxsIHsNCiAgMCUgeyB3aWR0aDogMDsgfQ17WyYqJl19Cn0NCg0KQGtleWZyYW1lcyBiYXItZmlsbCB7DQogIDAlIHsgd2lkdGg6IDA7IH0NCn1cIjt7WyYqJl19{!{/code}!}

Here, we define the keyframes for our animation. I’m only defining keyframes for Chrome and Safari using the -webkit prefix since the animation is only supported in those browsers. In this example, we are telling the animation to start at no width so that the bars will animate to their respective widths, based on the <value> properties we defined in the first step.

Putting it All Together

We’ve written our HTML, styled everything in CSS and even added a little support for animation. Putting everything together will give you a CSS bar chart that is responsive without using any media queries and uses no Javascript whatsoever.

Please make sure you consider browser support when using this technique, as it is not support by all browsers, especially older ones. Refer to Can I Use for the latest support information.

[codepen_embed height=”470″ theme_id=”279″ slug_hash=”FyBJk” default_tab=”result”]See the Pen CSS Bar Chart Using HTML5 Progress by Geoff Graham (@geoffgraham) on CodePen.[/codepen_embed]

Other Resources

✏️ Handwritten by Geoff Graham on January 14, 2014


  1. Luca Rossi
    # January 31, 2014

    hi dude, love your tutorials, but this one it doesn’t work fine! no animation and some style is missing…any help?

    • # January 31, 2014

      Hey Luca, thanks for writing!

      The support for HTML5 progress is still a little dodgy, so you’re likely to see differences. Check out Can I Use to see the latest browser support. Safari, Chrome, Firefox and Opera currently offer the best support.

      As far as the animations, only WebKit supports the ::progress-value pseudo-element (using the -webkit vendor prefix), so the animations are only supported in Safari and Chrome.

      WebKit and Mozilla are the only two engines that support styling HTML5 progress at the moment, and each uses their own vendor prefix and pseudo-element to do that. So, for example, to get the background color:

      // WebKit Background Color
      .foo::-webkit-progress-value { background: #ff9e2c; }

      // Mozilla Background Color
      .foo::-moz-progress-bar { background: #ff9e2c; }

      Hope this helps! You can also check out a pen of this demo to see it action.

    • Luca Rossi
      # February 1, 2014

      thanks gheoff, thanks for reply, i admit i m not so confortable with scripting….anyway I’m using your tips on chrome and safari putting your html into a section on my file and paste the lines of your Css, but there’s still no animation and no css to that!

      can you help me?

      here you can find the files i’m using…

    • # February 1, 2014

      Hey Luca,

      The tutorial was written in SCSS, so you will want to compile that to CSS before moving it into production. Thanks!

  2. # May 28, 2014

    Thanks Geoff, is it possible to slow down the animation? I think it would be sweet if it took a couple seconds to fill up the bar. Thanks

    • # May 28, 2014

      Hi Josh! Yep, you can to do that right on the ::-webkit-progress-value pseudo-element. It’s set to 2s in the demo, but could be anything you want in production.

    • # May 29, 2014

      Nice! That’s easy. Thanks!

  3. olo
    # June 11, 2014

    Is it possible to change the background color of the progress bar (the part that is gray)?

  4. bbpan
    # September 2, 2014

    This is awesome work. May I ask what I could do to make the bars go from right to left? One hack I could think of is switching the background color and use a percentage that is subtracted from 100%?

    • # September 3, 2014

      That’s interesting! You can try adding direction: rtl on the progress element in the CSS.

      Here’s what that looks like:

      From there, you can format the text as needed, or set the direction on the body as a whole to change the direction globally.

    • bbpan
      # September 3, 2014


  5. RJames
    # February 19, 2015

    Great tutorial, it worked perfectly. I was just wondering is there any way to get the animation to start once the user has scrolled to where the graph is located instead of as the page is opened.

    • candh
      # March 5, 2015

      you can use waypoints.js to trigger the animation

  6. Kessa
    # March 20, 2015

    Thanks for the tutorial, really helpful.

    1 small thing – the animation doesn’t seem to be working for me (have tried the demo on Codepen too to make sure I hadn’t inadvertently done something wrong, and have also tried the 2nd demo link you posted (re changing the progress bar background colour – both same result of just displaying statically).

    Have tested in Chrome
    (Version 41.0.2272.89 (64-bit)), and Firefox 34.0.5

    Any ideas? Thx

    • # April 2, 2015

      Yeah, this tutorial was written before Chrome forked off of WebKit and moved over to Blink. It appears the animation only holds in Safari.

  7. Leonard
    # April 7, 2015

    How to show the value ?

  8. Jonard nsomniart
    # June 23, 2015

    Is it possible to have multiple values depicted in a single bar or even have the entire chart a timeline?


Leave a Reply

Markdown supported