'How design a speedometer with HTML and CSS?

I am trying to design a speedometer as shown in the image:enter image description here

I'm having a hard time making that design with CSS. So I need help from a CSS master. How can I place the numbers like that, just like the blue bars.

So far what I tried grab this:

#speedometer .wrapper {
    width: 500px;
    height: 250px;
    border: 1px solid red;
    border-top-left-radius: 360px;
      border-top-right-radius: 360px;
    overflow: hidden;
    position: relative;
}

#speedometer .wrapper .indicator-wrapper {
    position: absolute;
    left: 10%;
    top: 20%;
    width: 80%;
    height: 80%;
    border-top-left-radius: 360px;
    border-top-right-radius: 360px;
    background-color: #ffffff;
    z-index: 400;
}

#speedometer .wrapper .bar {
    width: 100%;
    height: 100%;
    position: absolute;
    transform-origin: bottom center;
}

#speedometer .wrapper .bar-1 {
    top: 0;
    left: 0;
    z-index: 200;
    transform: rotate(-140deg);
    /* background-color: rgb(114, 114, 238); */
    background-color: green;
}

#speedometer .wrapper .bar-2 {
    top: 0;
    right: 0;
    z-index: 150;
    transform: rotate(-90deg);
    /* background-color: rgb(69, 69, 204); */
    background-color: yellow;
}

#speedometer .wrapper .bar-3 {
    top: 0;
    left: 0;
    z-index: 100;
    transform: rotate(-40deg);
    /* background-color: rgb(40, 40, 180); */
    background-color: purple;
}

#speedometer .wrapper .bar-4 {
    top: 0;
    left: 0;
    z-index: 0;
    transform: rotate(30deg);
    /* background-color: rgb(15, 15, 167); */
    background-color: red;
}
<div id="speedometer">
    <div class="wrapper">
        <div class="indicator-wrapper">
            <div class="indicator-wrapper-inner">
                <div id="indicator"></div>
            </div>
        </div>

        <div class="bar bar-1"></div>
        <div class="bar bar-2"></div>
        <div class="bar bar-3"></div>
        <div class="bar bar-4"></div>
    </div>
</div>

I need a lot of help to position the numbers like that, add the states: 'Good', 'Average', 'Bad', 'Very Bad' at the top. Likewise, add spacing between the bars. I know I'm asking a lot but the truth is costing me a lot. Thank you very much for your help



Solution 1:[1]

If you want to use just HTML and CSS you can put each number at the top of a long thin element which is then rotated about the bottom center of the speedometer.

There are 11 numbers so the number of degrees between each rotated element is 180/10;

Then each number is rotated back so it doesn't look rotated.

This snippet sets a CSS variable --num to the total number of numbers and uses CSS calc to calculate the rotations needed.

.speedometer {
  --num: 11;
  /* the total number of numbers */
  width: 100vmin;
  aspect-ratio: 2 / 1;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  position: relative;
}

.speedometer>* {
  position: absolute;
  bottom: 0;
  left: calc(50% - 1em);
  width: 2em;
  height: 70%;
  --deg: calc(180deg / calc(var(--num) - 1));
  transform: rotate(calc(-90deg + calc((var(--n) - 1) * var(--deg))));
  transform-origin: center bottom;
}

.speedometer>* * {
  display: flex;
  justify-content: center;
}

.speedometer>*>* {
  transform: rotate(calc(90deg - ((var(--n) - 1) * var(--deg))));
}

.speedometer> :nth-child(1) {
  --n: 1;
}

.speedometer> :nth-child(2) {
  --n: 2;
}

.speedometer> :nth-child(3) {
  --n: 3;
}

.speedometer> :nth-child(4) {
  --n: 4;
}

.speedometer> :nth-child(5) {
  --n: 5;
}

.speedometer> :nth-child(6) {
  --n: 6;
}

.speedometer> :nth-child(7) {
  --n: 7;
}

.speedometer> :nth-child(8) {
  --n: 8;
}

.speedometer> :nth-child(9) {
  --n: 9;
}

.speedometer> :nth-child(10) {
  --n: 10;
}

.speedometer> :nth-child(11) {
  display: inline-block;
  --n: 11;
}
<div class="speedometer">
  <div>
    <div>0</div>
  </div>
  <div>
    <div>10</div>
  </div>
  <div>
    <div>20</div>
  </div>
  <div>
    <div>30</div>
  </div>
  <div>
    <div>40</div>
  </div>
  <div>
    <div>50</div>
  </div>
  <div>
    <div>60</div>
  </div>
  <div>
    <div>70</div>
  </div>
  <div>
    <div>80</div>
  </div>
  <div>
    <div>90</div>
  </div>
  <div>
    <div>100</div>
  </div>
</div>

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 A Haworth