The Progress and Meter Tags

The Progress and Meter Tags

So far this year, I have been exploring many of the lesser-known tags in the HTML5 library. I’m continuing on with the <progress> and <meter> tags, as these two tags have some distinct similarities, but also some distinct differences. At their heart, both tags have the appearance of measuring what percentage of completion something is. Both <progress> and <meter> are progress-bar elements, however the difference in what is being measured between them is worth spending time to understand.

The basic syntax for a <progress> element is this:

<progress value="42" max="100">42%</progress>

And it looks like:



We’ll start with the <progress> tag. According to MDN, the <progress> tag represents the completion of a task, displayed as a progress bar. This is an excellent example of the type of element we see in form controls and other instances where HTML is providing us with a construct instead of just wrapping an invisible DOM rectangle around some content. As discussed in a previous post, the purpose of HTML is to give context to content. When we wrap a <p> tag around a sentence, we are giving context to that content, that it represents a paragraph in structure.

With the <progress> element, we’re talking about a different context. The data is represented by the construct we get. This is true technology at work, instead of just theoretical markup which can be interpreted by a human or a computer with relatively equal facility. With the <progress> element, we are relying on the client software of a browser to render this construct in a way that represents the context of the data. This means a visual element that is filled to some percentage, represented by the data we pass in as attributes. Attributes modify the context the HTML creates, and in the case of <progress> it is modifying it by quantifying the visual fill.


The <progress> element is going to take two attributes, standardly. First is the max attribute, which represents what value would completely fill the <progress> element. The other attribute is the value attribute, which represents the current fill value. The browser takes care of computing what percent the value is of the max.

The max attribute is required, but the value is not. If value is not present, your progress bar is in an “indeterminate” state, because there is no value to represent. This automatically generates an :indeterminate pseudo-element which can be styled (discussed in more detail below) to represent the state of the progress bar element with no value.

The text content of the <progress> element, as demonstrated above, is purely for legacy clients that will not render the visual construct of the progress bar itself.

There is another attribute of <progress> elements which can be accessed programmatically, and that is the position attribute, which reflects a float value which is computed by dividing the value attribute by the max attribute, and therefore represents the “position” of the fill, or percentage of progress represented by the element.

It is worth noting that the progress bar will respond to “Global Attributes”, those attributes which can be applied to every element. One of the more interesting of these which will impact the appearance of the element is the dir attribute. By default its value is ltr for left-to-right, but you can also set dir="rtl" and the directionality of the progress bar will be reversed, filling from the right to the left.


This is a minefield, compared to a lot of other elements that I have covered so far in my series. As this is a rendered construct, it is not as simple as changing properties such a background-color and color to get different effects on the progress bar. Even standard border styling will produce interesting, and often unintended, effects. Styling progress bars can only be done with pseudo-elements, custom to the progress bar element itself. However, as per the specification, you cannot use :before and :after pseudo-elements with progress bars, you are restricted to the custom pseudo-elements. These are still browser-prefixed, and are listed below:

  • ::-webkit-progress-bar
  • ::-webkit-progress-value
  • ::-webkit-progress-inner-element
  • ::-ms-fill
  • ::-moz-progress-bar
  • :indeterminate

Here is the default styling that exists in Chrome for the <progress> tag:

progress {
  -webkit-appearance: progress-bar;
  box-sizing: border-box;
  display: inline-block;
  height: 1em;
  width: 10em;
  vertical-align: -0.2em;

input, textarea, select, button, meter, progress {
  -webkit-writing-mode: horizontal-tb;


If you weren’t aware that there were multiple elements that created progress-bar-like effects, you can’t be faulted. And if you were forced at gunpoint to explain the difference between the <progress> and <meter> elements, I don’t know that many of you would survive that ultimatum. Those who are frequent readers of my blog would survive that Saw-like experience and be able to say that according to the spec, “The meter element represents a scalar measurement within a known range, or a fractional value; for example disk usage, the relevance of a query result, or the fraction of a voting population to have selected a particular candidate.”

What this tells us is that <meter> and <progress> have semantic meaning, while having similar visual cues for the user. It only reinforces what I reiterated above from my earlier post. HTML is about context of content, and not appearance. So, to summarize, <progress> represents units of work that are ongoing, whereas <meter> represents a snapshot reading at any given moment.

The basic syntax for a <meter> tag is:

<meter value="42" max="100">42 out of 100</meter>

And that would look like:

42 out of 100


The <meter> element has more attributes than <progress> does. Whereas <progress> just responds to two values, max and value, the <meter> element responds to both of those plus these other five:

  • min - This is the lower boundary of the represented range. It must be lower than max, and defaults to 0.
  • low - Get ready to be confused. This is the upper numeric bound of the low end of the measured range. It must be greater than min, but lower than max or high. Default is the same value of the min attribute, if unspecified or out of bounds.
  • high - This is the lower numeric bound of the high end of the measured range. Must be less than the max value, and greater than low and min. What low and high do is provide thresholds for the styling of the element. If the value is under the low or over the high, the meter changes colour, depending on the client.
  • optimum - This is the idea value, and must be within the range defined by min and max. This indicates where the “ideal” value should be. This could be between min and low, for instance, or even between high and max.
  • form - This attribute is interesting, because it allows you to connect your <meter> tag to a <form>. This opens up the ability to do things like connect the display of the <meter> to something like a range input. However, this is not actually documented in the W3C Spec on the <meter> tag, just in the MDN documentation. Your Mileage May Vary.

Here are some examples of the optimum, low, and high having an effect:


<meter low="30" optimum="66" high="80" value="20" max="100">30 / 100</meter>

30 / 100


<meter low="30" optimum="66" high="80" value="66" max="100">30 / 100</meter>

30 / 100


<meter low="30" optimum="66" high="80" value="86" max="100">30 / 100</meter>

30 / 100


As with the values discussed above for the <progress> tag, the <meter> tag requires pseudo-classes for styling the various parts of the display. Here is the (long) list of prefixed pseudo-classes/elements that you have to address with styling to get any difference in appearance:

-webkit-meter-inner-elementHelps render the element as read-only
-webkit-meter-barContainer of the meter gauge that holds the value
-webkit-meter-optimum-valueStyling for specifically when the meter is at optimum value
-webkit-meter-suboptimum-valueStyling for when the value is below optimum. Normally this is yellow.
-webkit-meter-even-less-good-valueNot making this up! This is when the meter would normally be red.
-moz-meter-barSame as -webkit-meter-bar above
-moz-meter-optimumSame as -webkit-meter-optimum-value above
-moz-meter-sub-optimumSame as -webkit-meter-suboptimum-value above
-moz-meter-sub-sub-optimumAgain, I can’t make these names up. Same as -webkit-meter-even-less-good-value above

Additionally, just as with the <progress> bar, you may have varying results with adding :before and :after pseudo-elements to your <meter> bar. Here is the default styling in Chrome for a <meter> tag:

meter {
  -webkit-appearance: meter;
  box-sizing: border-box;
  display: inline-block;
  height: 1em;
  width: 5em;
  vertical-align: -0.2em;
  -webkit-user-modify: read-only;

input, textarea, select, button, meter, progress {
  -webkit-writing-mode: horizontal-tb;


Here we have two progress elements with very different appearances, but also different meanings and contexts within which to display data. These would be bad for displaying someone’s weight, but great for displaying something like disk usage, fuel tank status, or percentage that is complete in a task. I encourage you to play with these and include them in your coding.

Similar Posts