1👍
Two ideas that don’t require any frameworks:
1. CSS Conic gradients
I wonder if you could pull this off using CSS conic gradients. You could use a repeating conic gradient for the dashes, and a regular conic gradient for the filled value.
Note: This approach won’t work in IE because IE doesn’t have conic-gradient support.
Proof of concept:
body {
/*
Set up a couple custom properties to specify the colors.
You could hard-code them if you prefer, but this avoids
having to repeat the same color in various places and makes
it easier to change later
*/
--fgcolor: #346b79;
--bgcolor: #04151f;
/* set the background color for the page */
background: var(--bgcolor);
}
.demo {
/* make the div a circle. 400px is arbitrary. */
width: 400px;
height: 400px;
border-radius: 50%;
/*
Here's the magic part. one conic gradient to fill the "value" area
and a second, repeating conic gradient, to make the dashes. The dashes
go all the way around but get covered by the fill.
*/
background-image:
conic-gradient(var(--fgcolor) 0deg, var(--fgcolor) 204deg, transparent 204deg),
repeating-conic-gradient(var(--fgcolor) 0deg 0.5deg, var(--bgcolor) 0.5deg 2deg);
/* center the contents on both axes */
display: flex;
justify-content: center;
align-items: center;
/* just gives it some room on the page, centers it. */
margin: 1rem auto;
}
.demo > span {
/* The "value" element */
/* Sets the size of the inner circle.*/
width: 70%;
height: 70%;
/* fill the center with the background color */
background: var(--bgcolor);
/* make it a circle */
border-radius: 50%;
/* center the value on both axes */
display: flex;
justify-content: center;
align-items: center;
/* text treatment */
color: white;
font-size: 5rem;
font-family: sans-serif;
font-weight: bold;
}
<div class="demo">
<span>64%</span>
</div>
2. SVG stroke-dasharray
Creating an SVG that does this is pretty straightforward. You’d create a circle and an arc, each with a stroke. The circle would use stroke-dasharray to create the dashes, and the arc would fill in the "value" area.
Proof of concept:
body {
--fgcolor: #346b79;
--bgcolor: #04151f;
background: var(--bgcolor);
}
svg {
width: 300px;
height: 300px;
stroke: var(--fgcolor);
}
.dashes {
stroke-width: 15;
stroke-dasharray: 0.5px 2px;
}
.value {
stroke-width: 15;
}
text {
font-family: sans-serif;
font-weight: bold;
text-anchor: middle;
}
<svg viewBox="0 0 100 100">
<circle class="dashes" r="40" cx="50" cy="50" fill="none" />
<path class="value" d="M 50 10 A 40 40 0 1 1 24.50304 80.820529" fill="none" />
<text x=50 y=55 fill="white" stroke="none">64%</text>
</svg>
The path/arc part can seem a bit intimidating, but here’s what it does:
d="M 50 10 A 40 40 0 1 1 24.50304 80.820529"
M 50 50
Moves to (50, 50) to start drawing from there.
A 40 40 0 1 1 24.50304 80.820529
Draws an arc with a radius of 40 on both axes with its endpoint at (24.50304, 80.820529)
. The middle three arguments can be confusing and I don’t think I can explain them any better than MDN does so I’d point you there for details.
Calculating those endpoints isn’t particularly hard.
You take the sine and cosine (for x and y respectively) of the ending angle, multiply it by the radius of the circle, and add the circle’s center coordinate.
// for a value of 64%, a radius of 40, and center at [50,50]
const value = 0.64;
const radius = 40;
const cx = 50;
const cy = 50;
const endAngleDegrees = 360 * value;
const endAngleRadians = endAngleDegrees / (180/Math.PI);
const x = Math.sin(endAngleRadians) * radius + cx;
const y = Math.cos(endAngleRadians) * radius + cy;