The Progress and Meter Tags
- June 20, 2017
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:
Progress
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.
Attributes
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.
Styling
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;
}
Meter
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:
Attributes
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 thanmax
, 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 thanmin
, but lower thanmax
orhigh
. Default is the same value of themin
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 themax
value, and greater thanlow
andmin
. Whatlow
andhigh
do is provide thresholds for the styling of the element. If thevalue
is under thelow
or over thehigh
, the meter changes colour, depending on the client.optimum
- This is the idea value, and must be within the range defined bymin
andmax
. This indicates where the “ideal” value should be. This could be betweenmin
andlow
, for instance, or even betweenhigh
andmax
.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:
Low
<meter low="30" optimum="66" high="80" value="20" max="100">30 / 100</meter>
Optimum
<meter low="30" optimum="66" high="80" value="66" max="100">30 / 100</meter>
High
<meter low="30" optimum="66" high="80" value="86" max="100">30 / 100</meter>
Styling
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:
Pseudo-class | Description |
---|---|
-webkit-meter-inner-element | Helps render the element as read-only |
-webkit-meter-bar | Container of the meter gauge that holds the value |
-webkit-meter-optimum-value | Styling for specifically when the meter is at optimum value |
-webkit-meter-suboptimum-value | Styling for when the value is below optimum. Normally this is yellow. |
-webkit-meter-even-less-good-value | Not making this up! This is when the meter would normally be red. |
-moz-meter-bar | Same as -webkit-meter-bar above |
-moz-meter-optimum | Same as -webkit-meter-optimum-value above |
-moz-meter-sub-optimum | Same as -webkit-meter-suboptimum-value above |
-moz-meter-sub-sub-optimum | Again, 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;
}
Summary
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.