'Make bar/progress chart with JS and CSS [closed]
Solution 1:[1]
The most straightforward approach is to use an absolutely positioned child in a relatively positioned parent and set its width as the progress.
function setProgress(percent) {
const range = document.querySelector('.range');
const progress = range.querySelector('.progress');
progress.style.width = `${percent}%`
}
setProgress(70);
.range {
position: relative;
height: 20px;
background-color: #ed3a23;
border: 2px solid #000;
box-sizing: border-box;
overflow: hidden;
}
.progress {
position: absolute;
left: 0;
top: 0;
width: 0;
height: 100%;
background-color: #4db24c;
border-right: 3px solid #000;
}
<div class="range">
<div class="progress"></div>
</div>
Solution 2:[2]
You don't need JavaScript.
Pass a CSS var() from HTML to CSS and use calc() to get the percentages
Using background linear gradient
.progress {
background: green;
height: 2em;
background: linear-gradient(to right, green calc(var(--val) * 10%), red calc(var(--val) * 10%));
background-size: 100%;
}
<div class="progress" style="--val:1"></div><br>
<div class="progress" style="--val:7"></div><br>
Using CSS pseudo element ::before
.progress {
background: red;
height: 2em;
}
.progress::before {
content: "";
display: block;
height: inherit;
background: green;
width: calc(var(--val) * 10%);
}
<div class="progress" style="--val:1"></div><br>
<div class="progress" style="--val:7"></div><br>
Solution 3:[3]
Here's pure HTML & CSS
.bar-wrap {
display: flex
}
.col {
display: block;
text-align:center;
width: var(--size)
}
.bar {
height: 50px;
width: 100%;
border: 3px solid #000;
background: var(--background)
}
.cgreen {
color: green
}
.cred {
color: red
}
<div class="bar-wrap">
<div class="col cgreen" style="--size:70%;">
<h3 class="heading">Correct</h3>
<div class="bar" style="--background:green"></div>
<p class="label">70%</p>
</div>
<div class="col cred" style="--size:30%;">
<h3 class="heading">Wrong</h3>
<div class="bar" style="--background:red"></div>
<p class="label">30%</p>
</div>
</div>
Solution 4:[4]
To meet accessibility and semantic code standards, I'd recommend having a look into the HTML <meter> element (official specification with all the attributes). Or you just have a look on HTML5 doctor to get a more compact/short conclusion.
However, keep in mind that according to caniuse.com, legacy browsers like Edge 12 and others don't support this HTML tag. So if you want to support these older browsers, that are listed there as non-supporting, you would need to come up with a fallback solution.
Rough code example for a fallback solution
<div class="meter-wrapper">
<div class="meter" style="width: 70%;">
<!-- `hidden` attribute to hide the text content but keeping the element accessible for screen readers. -->
<p class="meter__text-fallback meter__text-fallback--correct"><strong>70%</strong><span hidden>of given answers are correct.</span></p>
</div>
<p class="meter__text-fallback meter__text-fallback--incorrect"><strong>30%</strong><span hidden>of given answers are incorrect.</span></p>
</div>
and style it something like this:
/* CSS */
.meter-wrapper {
background-color: pink;
height: 40px;
position: relative;
}
.meter {
display: inline-block;
background-color: MediumAquamarine;
height: 100%;
position: relative;
}
.meter__text-fallback {
position: absolute;
margin: 0;
bottom: -25px;
}
/* This class block is not utterly necessary, since the default value for `left` is already `0`. Just in case you want to have different values. */
.meter__text-fallback--correct {
left: 0;
}
.meter__text-fallback--incorrect {
right: 0;
}
See this code example in action
Important notes to this code example
I would recommend to change your layout from having the percentage of correct and incorrect answers outside the meter bars to avoid a case, where you would have a slimmer bar than the width of the typography overlapping it.
Setting the values for the
style="width: 70%"attributes would need to be controlled via JS. It is also arguable to style HTML elements with inline styles, like I did in this example. On the other hand creating a 100+ different CSS classes for such a case, might be overkill. Styling viadataattributes is also not fully supported. So I'll leave this decision up to you.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | pouria |
| Solution 2 | |
| Solution 3 | |
| Solution 4 | Kayzah |

