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

<ul class="skill-list">
  <li class="skill">
    <progress class="skill-1" max="100" value="50">
      <strong>Skill Level: 50%</strong>
  <li class="skill">
    <h3>Bow Staff</h3>
    <progress class="skill-2" max="100" value="75">
      <strong>Skill Level: 75%</strong>
  <li class="skill">
    <h3>Roundhouse Kick</h3>
    <progress class="skill-3" max="100" value="25">
      <strong>Skill Level: 25%</strong>


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.

progress, progress[role] {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  border: none;
  background-size: auto;
  height: 100px;
  width: 100%;

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.

// The unordered list
.skill-list {
  list-style: none;
  margin: 0;
  padding: 1em;

// The list item
.skill {
  margin-bottom: 1em;
  position: relative;
  h3 {
    color: #fff;
    font-size: 2em;
    font-family: "Helvetica Neue", arial, sans-serif;
    left: 1em;
    line-height: 1;
    position: absolute;
    top: 1em;
  ::-webkit-progress-value { 
    -webkit-animation: bar-fill 2s;
    width: 0px;

// The background colors
.skill-1::-webkit-progress-value {
  background: #ff9e2c;

.skill-1::-moz-progress-bar {
  background: #ff9e2c;

.skill-2::-webkit-progress-value {
  background: #4ecdc4;

.skill-2::-moz-progress-bar {
  background: #4ecdc4;

.skill-3::-webkit-progress-value {
  background: #ff6b6b;

.skill-3::-moz-progress-bar {
  background: #ff6b6b;

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.

 // The keyframes
@-webkit-keyframes bar-fill {
  0% { width: 0; }

@keyframes bar-fill {
  0% { width: 0; }

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.

See the Pen CSS Bar Chart Using HTML5 Progress by Geoff Graham (@geoffgraham) on CodePen.279

Other Resources


Subscribe to Devigner Digest

I read a lot of crap about design and development and 90% really is crap. Subscribe and I will send links to the other 10% about once a month.