htmlcsssvg

Simple svg css progress circle


I am trying to look for a way to achieve a simple progress circle (static) with no animations. The examples I have found have very different offsets for percentage such as given in the example below. How do I make my progress circle in such a way that if I provide offset as 50%, then it is exactly 50% (half filled)?

.u-absoluteCenter {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
}
.u-flexCenter {
  display: flex;
  align-items: center;
  justify-content: center;
}
.u-offscreen {
  position: absolute;
  left: -999em;
}
.demo {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.progress {
  transform: rotate(-90deg);
}
.progress__value {
  stroke-dasharray: 0;
  stroke-dashoffset: 0;
}
@-webkit-keyframes progress {
  from {
    stroke-dashoffset: 339.292;
  }
  to {
    stroke-dashoffset: 0;
  }
}
@keyframes progress {
  from {
    stroke-dashoffset: 339.292;
  }
  to {
    stroke-dashoffset: 0;
  }
}
<svg width="120" height="120" viewBox="0 0 120 120">
    <circle cx="60" cy="60" r="54" fill="none" stroke="#e6e6e6" stroke-width="12" />
    <circle cx="60" cy="60" r="54" fill="none" stroke="#f77a52" stroke-width="12"
        stroke-dasharray="339.292" stroke-dashoffset="339.292" />
</svg>


Solution

  • You can leverage an SVG attribute to set the path length rather than having to calculate it.

    pathLength sets the length to whatever you need...say 100 for a progress bar.

    The pathLength attribute lets authors specify a total length for the path, in user units. This value is then used to calibrate the browser's distance calculations with those of the author, by scaling all distance computations using the ratio pathLength/(computed value of path length).

    pathLength="100"
    

    Then you can set the stroke-dasharray to 100 as well and then adjust the stroke-dashoffset as needed....

    ::root {
      --val: 0;
    }
    
    svg {
      transform: rotate(-90deg);
    }
    
    .percent {
      stroke-dasharray: 100;
      stroke-dashoffset: calc(100 - var(--val));
    }
    
    .fifty {
      --val: 50;
    }
    
    .sixty {
      --val: 60;
    }
    
    .ninety {
      --val: 90;
    }
    <svg width="120" height="120" viewBox="0 0 120 120">
        <circle cx="60" cy="60" r="54" fill="none" stroke="#e6e6e6" stroke-width="12" />
        <circle class="percent fifty" cx="60" cy="60" r="54" fill="none" stroke="#f77a52" stroke-width="12" pathLength="100" />
    </svg>
    
    <svg width="120" height="120" viewBox="0 0 120 120">
        <circle cx="60" cy="60" r="54" fill="none" stroke="#e6e6e6" stroke-width="12" />
        <circle class="percent sixty" cx="60" cy="60" r="54" fill="none" stroke="#f77a52" stroke-width="12" pathLength="100" />
    </svg>
    
    
    <svg width="120" height="120" viewBox="0 0 120 120">
        <circle cx="60" cy="60" r="54" fill="none" stroke="#e6e6e6" stroke-width="12" />
        <circle class="percent ninety" cx="60" cy="60" r="54" fill="none" stroke="#f77a52" stroke-width="12" pathLength="100" />
    </svg>