Search code examples
htmlcsssvgcss-shapes

Circular percent progress bar


I would like to have an percent circle indicator on my site:

Radial progress bar mockup

In this case it's showing 75%. How should this be done? I have the yellow circle in a image-file, but if it's easier to, some how, do it all using CSS, that's okay with me.


Solution

  • Considering the shape of the progress bar (rounded end/start) I would suggest using SVG.

    DEMO: Radial progress bar

    Radial progress bar

    In the following example, the progress is animated with the stroke-dasarray attribute and the % numbers are incremented with jQuery:

    var count = $(('#count'));
    $({ Counter: 0 }).animate({ Counter: count.text() }, {
      duration: 5000,
      easing: 'linear',
      step: function () {
        count.text(Math.ceil(this.Counter)+ "%");
      }
    });
    body{text-align:center;font-family: 'Open Sans', sans-serif;}
    svg{width:25%;}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <svg id="animated" viewbox="0 0 100 100">
      <circle cx="50" cy="50" r="45" fill="#FDB900"/>
      <path fill="none" stroke-linecap="round" stroke-width="5" stroke="#fff"
            stroke-dasharray="251.2,0"
            d="M50 10
               a 40 40 0 0 1 0 80
               a 40 40 0 0 1 0 -80">
        <animate attributeName="stroke-dasharray" from="0,251.2" to="251.2,0" dur="5s"/>           
      </path>
      <text id="count" x="50" y="50" text-anchor="middle" dy="7" font-size="20">100%</text>
    </svg>


    Unfortunatly IE doesn't support svg SMIL animations. To achieve the same result with IE support, you can use a library like snap.svg and animate the stroke-dasharray attribute with JS :

    var count = $(('#count'));
    $({ Counter: 0 }).animate({ Counter: count.text() }, {
      duration: 5000,
      easing: 'linear',
      step: function () {
        count.text(Math.ceil(this.Counter)+ "%");
      }
    });
    
    var s = Snap('#animated');
    var progress = s.select('#progress');
    
    progress.attr({strokeDasharray: '0, 251.2'});
    Snap.animate(0,251.2, function( value ) {
        progress.attr({ 'stroke-dasharray':value+',251.2'});
    }, 5000);
    body{text-align:center;font-family:sans-serif;}
    svg{width:25%;}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
    <svg id="svg" viewbox="0 0 100 100">
      <circle cx="50" cy="50" r="45" fill="#FDB900"/>
      <path fill="none" stroke-linecap="round" stroke-width="5" stroke="#fff"
            stroke-dasharray="1,250.2"
            d="M50 10
               a 40 40 0 0 1 0 80
               a 40 40 0 0 1 0 -80"/>
      <text x="50" y="50" text-anchor="middle" dy="7" font-size="20">1%</text>
    </svg>
    <svg viewbox="0 0 100 100">
      <circle cx="50" cy="50" r="45" fill="#FDB900"/>
      <path fill="none" stroke-linecap="round" stroke-width="5" stroke="#fff"
            stroke-dasharray="125.6,125.6"
            d="M50 10
               a 40 40 0 0 1 0 80
               a 40 40 0 0 1 0 -80"/>
      <text x="50" y="50" text-anchor="middle" dy="7" font-size="20">50%</text>
    </svg>
    
    <svg id="animated" viewbox="0 0 100 100">
      <circle cx="50" cy="50" r="45" fill="#FDB900"/>
      <path id="progress" stroke-linecap="round" stroke-width="5" stroke="#fff" fill="none"
            d="M50 10
               a 40 40 0 0 1 0 80
               a 40 40 0 0 1 0 -80">
      </path>
      <text id="count" x="50" y="50" text-anchor="middle" dy="7" font-size="20">100%</text>
    </svg>