Frontend Development 9 min read

Implementing a Circular Dashboard Gauge in H5 Using Pure HTML, CSS, and JavaScript

This article documents a step‑by‑step exploration of four native HTML/CSS/JS approaches to create an animated circular dashboard gauge on an H5 page, discusses the challenges encountered, and presents a final SVG‑based solution with code examples.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implementing a Circular Dashboard Gauge in H5 Using Pure HTML, CSS, and JavaScript

The article describes the process of building a circular dashboard gauge in an H5 page without relying on third‑party libraries, evaluating four different implementations and summarizing the lessons learned.

Requirement

The UI needs a ring‑shaped gauge that animates from 0% to the actual percentage, as illustrated by the accompanying image.

Premise

The implementation must use only native HTML, CSS, and JavaScript.

Initial Solution

Use the UI image as a background, overlay a white div as a mask, and rotate the mask with CSS3 transforms.

Code

<style>
	.light-strip {
		width: 500px;
		height:500px;
		border: 1px solid #efefef;
		background-image: url('Frame [email protected]');
		float: right;
		background-size: 100% 100%;
	}
	.light-strip-top {
		margin-top: 0%;
		width: 500px;
		height: 250px;
		background: #fff;
		transform-origin: bottom center;
		rotate: 0deg;
		transition: all 2s ease-in-out;
	}
</style>
<body onload="load()">
	<div class="light-strip">
		<div class="light-strip-top"></div>
	</div>
</body>
<script>
	function load() {
		setTimeout(() => {
			document.querySelectorAll('.light-strip-top')[0].setAttribute('style', "rotate: 180deg")
		}, 1000)
	}
</script>

The effect works, but because the gauge exceeds 180°, the white mask initially covers the whole gauge and later obscures the UI image after rotation.

Evolution Plan

One idea was to ask the UI designer to limit the gauge to 180°, but the resulting visual was considered unattractive.

Super Evolution Plan

Replace the white mask with a pointer image and rotate it, achieving a similar transition while still altering the UI appearance.

Code

<style>
	.light-strip {
		width: 500px;
		height:500px;
		border: 1px solid #efefef;
		background-image: url('Frame [email protected]');
		float: right;
		background-size: 100% 100%;
	}
	.light-strip-top {
		margin-top: 50%;
		width: 49%;
		height: 4px;
		background: red;
		transform-origin: center right;
		rotate: -35deg;
		transition: all 2s ease-in-out;
	}
</style>
<body onload="load()">
	<div class="light-strip">
		<div class="light-strip-top"></div>
	</div>
</body>
<script>
	function load() {
		setTimeout(() => {
			document.querySelectorAll('.light-strip-top')[0].setAttribute('style', "rotate: 90deg")
		}, 1000)
	}
</script>

This approach also modifies the UI and did not fully solve the problem.

Current Situation

Having exhausted the previous ideas, the author explored Element‑Plus progress bars and decided to try an SVG‑based implementation.

Ultimate Evolution Plan

Use SVG to create a white background ring (A) and a colored progress ring (B); manipulate stroke-dasharray , stroke-dashoffset , and CSS transitions to animate the gauge.

Code

<style>
    body {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100vh;
      margin: 0;
      background-color: #f5f5f5;
    }
    .dashboard {
      position: relative;
      width: 200px;
      height: 200px;
      background-size: 100% 100%;
    }
    .circle-background {
      fill: none;
      stroke: #fff;
      stroke-width: 10;
      stroke-dasharray: 200, 52;
      stroke-dashoffset: 163;
      stroke-linecap: round;
      transition: all 1s;
    }
    .circle-progress {
      fill: none;
      stroke: url(#gradient);
      stroke-width: 10;
      stroke-dasharray: 252, 0;
      stroke-dashoffset: 163;
      stroke-linecap: round;
      transition: all 1s;
    }
    .percentage {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 24px;
      color: #3498db;
    }
</style>
<svg class="dashboard" viewBox="0 0 100 100">
  <defs>
    <linearGradient id="gradient" gradientUnits="userSpaceOnUse" x1="50" y1="0" x2="50" y2="100%">
      <stop offset="0%" style="stop-color: rgba(111, 232, 191, 1)" />
      <stop offset="33%" style="stop-color: rgba(255, 175, 19, 1)" />
      <stop offset="70%" style="stop-color: rgba(222, 19, 80, 1)" />
      <stop offset="100%" style="stop-color: rgba(133, 14, 205, 1)" />
    </linearGradient>
  </defs>
  <circle class="circle-background" cx="50" cy="50" r="40"></circle>
  <circle class="circle-progress" cx="50" cy="50" r="40"></circle>
</svg>
<div class="percentage" id="percentage">0%</div>
<script>
  function setProgress(percentage) {
    const circleProgress = document.querySelector('.circle-progress');
    const circleBackground = document.querySelector('.circle-background');
    const percentageText = document.getElementById('percentage');
    const circumference = 2 * Math.PI * 40;
    const circumNewLength = (percentage / 100) * (circumference - 52);
    const dashOffset = 163 - circumNewLength;
    circleBackground.style.strokeDashoffset = dashOffset;
    circleBackground.style.strokeDasharray = `${200 - circumNewLength}, ${ 52 + circumNewLength }`;
    circleProgress.style.strokeDasharray = `${circumNewLength}, ${ circumference - circumNewLength }`;
    percentageText.textContent = `${percentage}%`;
  }
  setProgress(0);
  setTimeout(() => {
    setProgress(50);
  }, 1000);
</script>

The implementation works, but the gradient transition is linear between two points and cannot produce a clockwise color sweep around the ring.

Summary

Simple pre‑setup is not a cure‑all 😂😂😂😂

The author believes the requirement is still achievable.

Requests experienced developers to propose a solution.

Encouragement to keep experimenting.

frontendanimationJavaScriptDashboardSVGCSShtml
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.