Circle Progress Bar

So you want a circular progress bar? You can do it with an SVG <path/>. The trick is getting the path to draw a perfect semicircle from one angle to another. Here's some code:
<style> /* Give it some style. Don't worry about the size or the stroke width, we need to set that in the script later. */ path { fill: none; stroke: #fff; } </style> <svg id="svg"> <path id="path"/> </svg> <script> function render(progress = 0) { // The path to be drawn depends on the diameter of the // shape, and the stroke width of the line you want. // All of this can be hard-coded, just replace the constants // with the values you need. const STROKE_WIDTH = 8; const DIAMETER = 100; const SVG_ELEMENT = document.getElementById("svg"); const PATH_ELEMENT = document.getElementById("path"); SVG_ELEMENT.setAttribute('viewbox', `0 0 ${DIAMETER} ${DIAMETER}`); SVG_ELEMENT.setAttribute('width', DIAMETER); SVG_ELEMENT.setAttribute('height', DIAMETER); PATH_ELEMENT.setAttribute('stroke-width', STROKE_WIDTH); // Math... yuck. let draw = [ "M", DIAMETER/2 + (DIAMETER/2-STROKE_WIDTH/2) * Math.cos((progress*359.9-90) * Math.PI/180.0), DIAMETER/2 + (DIAMETER/2-STROKE_WIDTH/2) * Math.sin((progress*359.9-90) * Math.PI/180.0), "A", DIAMETER/2 - STROKE_WIDTH/2, DIAMETER/2 - STROKE_WIDTH/2, 0, progress * 360 > 180 ? 1 : 0, 0, DIAMETER/2, STROKE_WIDTH/2, ].join(' '); PATH_ELEMENT.setAttribute('d', draw); } // Animation is just for show. In the wild, // render the real progress from 0 to 1. let p = 0; setInterval(() => render(p = (p + 0.01) % 1), 50); </script>
See it in action.