How to create dashed circles with uniform spacing?

后端 未结 2 817
小蘑菇
小蘑菇 2020-12-05 15:05

I wanted to make a dotted circle with CSS and created it with the following process.

Although the dashed circle could be displayed by this process, The gap between t

相关标签:
2条回答
  • 2020-12-05 15:39

    Here is an optimized version of the conic-gradient() solution where you can easily control the number of dashes and the space between

    .box {
      --d:4deg; /* distance between dashes */
      --n:30;   /* number of dashes */
      --c:#000; /* color of dashes */
      width: 180px;
      display:inline-block;
      border-radius:50%;
      border:2px solid transparent; /* control the thickness of border*/
      background: 
        linear-gradient(#fff,#fff) padding-box padding-box,
        repeating-conic-gradient(
            var(--c)    0 calc(360deg/var(--n) - var(--d)), 
            transparent 0 calc(360deg/var(--n)) 
        ) border-box;
    }
    
    /* keep the element square */
    .box:before {
      content:"";
      display:block;
      padding-top:100%;
    }
    <div class="box"></div>
    
    <div class="box" style="--n:20;border-width:5px;width:150px"></div>
    
    <div class="box" style="--n:8;--d:20deg;border-width:5px;width:150px"></div>
    
    <div class="box" style="--n:10;--d:15deg;border-width:3px;width:100px"></div>
    
    <div class="box" style="--n:10;--d:20deg;border-width:3px;width:100px"></div>

    To have full transparency we consider mask

    .box {
      --d:4deg; /* distance between dashes */
      --n:30;   /* number of dashes */
      --c:#000; /* color of dashes */
      --b:2px;   /* control the thickness of border*/
      
      width: 180px;
      display:inline-block;
      border-radius:50%;
      background: 
        repeating-conic-gradient(
            var(--c)    0 calc(360deg/var(--n) - var(--d)), 
            transparent 0 calc(360deg/var(--n)));
      -webkit-mask:radial-gradient(farthest-side,transparent calc(100% - var(--b)),#fff calc(100% - var(--b) + 1px));
              mask:radial-gradient(farthest-side,transparent calc(100% - var(--b)),#fff calc(100% - var(--b) + 1px));
    }
    
    /* keep the element square */
    .box:before {
      content:"";
      display:block;
      padding-top:100%;
    }
    
    
    body {
      background:linear-gradient(to right,yellow,pink);
    }
    <div class="box"></div>
    
    <div class="box" style="--n:20;--b:5px;width:150px;--c:blue"></div>
    
    <div class="box" style="--n:8;--d:20deg;--b:10px;width:130px;--c:red"></div>
    
    <div class="box" style="--n:18;--d:12deg;--b:8px;width:100px;--c:green"></div>
    
    <div class="box" style="--n:10;--d:20deg;--b:3px;width:100px;--c:purple"></div>

    To make things funny we can even consider a more complex coloration to the dashes:

    .box {
      --d:4deg; /* distance between dashes */
      --n:30;   /* number of dashes */
      --b:2px;   /* control the thickness of border*/
      
      width: 180px;
      display:inline-block;
      border-radius:50%;
      background:linear-gradient(red,blue);
      -webkit-mask:
          radial-gradient(farthest-side,transparent calc(100% - var(--b)),#fff calc(100% - var(--b) + 1px)),
          repeating-conic-gradient(#000 0 calc(360deg/var(--n) - var(--d)),transparent 0 calc(360deg/var(--n)));
      -webkit-mask-composite: source-in;
              mask:
          radial-gradient(farthest-side,transparent calc(100% - var(--b)),#fff calc(100% - var(--b) + 1px)),
          repeating-conic-gradient(#000 0 calc(360deg/var(--n) - var(--d)),transparent 0 calc(360deg/var(--n)));
              mask-composite: intersect;
    }
    
    /* keep the element square */
    .box:before {
      content:"";
      display:block;
      padding-top:100%;
    }
    
    
    body {
      background:linear-gradient(to right,yellow,pink);
    }
    <div class="box"></div>
    
    <div class="box" style="--n:20;--b:5px;width:150px;background:conic-gradient(green,orange,black)"></div>
    
    <div class="box" style="--n:8;--d:20deg;--b:10px;width:130px;background:conic-gradient(black,white,black)"></div>
    
    <div class="box" style="--n:18;--d:12deg;--b:8px;width:100px;background:linear-gradient(60deg,red 50%,green 0)"></div>
    
    <div class="box" style="--n:10;--d:20deg;--b:3px;width:100px;background:#fff"></div>

    You may for sure want some content inside so better apply the mask/background on a pseudo element to avoid masking the content:

    .box {
      --d:4deg; /* distance between dashes */
      --n:30;   /* number of dashes */
      --b:2px;   /* control the thickness of border*/
      
      width: 180px;
      display:inline-flex;
      justify-content:center;
      align-items:center;
      font-size:35px;
      border-radius:50%;
      position:relative;
    }
    .box::after {
      content:"";
      position:absolute;
      top:0;
      left:0;
      right:0;
      bottom:0;
      z-index:-1;
      border-radius:inherit;
      background:var(--c,linear-gradient(red,blue));
      -webkit-mask:
          radial-gradient(farthest-side,transparent calc(100% - var(--b)),#fff calc(100% - var(--b) + 1px)),
          repeating-conic-gradient(#000 0 calc(360deg/var(--n) - var(--d)),transparent 0 calc(360deg/var(--n)));
      -webkit-mask-composite: source-in;
              mask:
          radial-gradient(farthest-side,transparent calc(100% - var(--b)),#fff calc(100% - var(--b) + 1px)),
          repeating-conic-gradient(#000 0 calc(360deg/var(--n) - var(--d)),transparent 0 calc(360deg/var(--n)));
              mask-composite: intersect;
      
    }
    
    /* keep the element square */
    .box:before {
      content:"";
      padding-top:100%;
    }
    
    
    body {
      background:linear-gradient(to right,yellow,pink);
    }
    <div class="box">19</div>
    
    <div class="box" style="--n:20;--b:5px;width:150px;--c:conic-gradient(green,orange,black)">17</div>
    
    <div class="box" style="--n:8;--d:20deg;--b:10px;width:130px;--c:conic-gradient(black,white,black)">5</div>
    
    <div class="box" style="--n:18;--d:12deg;--b:8px;width:100px;--c:linear-gradient(60deg,red 50%,green 0)">9</div>
    
    <div class="box" style="--n:10;--d:20deg;--b:3px;width:100px;--c:#fff">13</div>


    Related question to get more CSS ideas to achieve a similar result: CSS Only Pie Chart - How to add spacing/padding between slices?. You will find more supported ways than conic-gradient() (actually it doesn't work on Firefox) but you are required to use a lot of code unlike the above solution where only one element is needed.


    Using SVG you will also need some calculation to make sure you have a uniform spacing:

    svg {
      width:200px;
    }
    <svg viewBox="-3 -3 106 106">
      <!-- 
        The circumference of the circle is 2*PI*R ~ 314.16
        if we want N dashed we use d=314.16/N
        For N = 20 we have d=15.71
        For a gap of 5 we will have "10.71,5" (d - gap,gap)
      -->
      <circle cx="50" cy="50" r="50" 
        stroke-dasharray="10.71, 5" 
        fill="transparent" 
        stroke="black" 
        stroke-width="5" />
    </svg>

    With CSS variables we can make it easier but it's not supported in all the browser (actually it doesn't work in Firefox)

    svg {
      --n:20; /* number of dashes*/
      --d:5;  /* distance */
      width:200px;
    }
    
    svg circle {
       stroke-dasharray:calc((2*3.14*50)/var(--n) - var(--d)), var(--d); 
    }
    <svg viewBox="-3 -3 106 106">
      <circle cx="50" cy="50" r="50" fill="transparent" stroke="black" stroke-width="5" />
    </svg>
    
    <svg viewBox="-3 -3 106 106" style="width:150px;--n:20;--d:10">
      <circle cx="50" cy="50" r="50" fill="transparent" stroke="red"   stroke-width="5" />
    </svg>
    
    <svg viewBox="-3 -3 106 106" style="width:100px;--n:8;--d:15">
      <circle cx="50" cy="50" r="50" fill="transparent" stroke="green" stroke-width="5" />
    </svg>

    We can also easily use the SVG as background to make things more flexible:

    .box {
      display:inline-block;
      width:200px;
      background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-3 -3 106 106"><circle cx="50" cy="50" r="50" fill="transparent" stroke="black" stroke-width="5" style="stroke-dasharray:29.25, 10" /></svg>') center/contain;
    }
    
    .box:before {
      content:"";
      display:block;
      padding-top:100%;
    }
    <div class="box">
    
    </div>
    
    <div class="box" style="width:150px;">
    
    </div>
    
    <div class="box" style="width:100px;">
    
    </div>

    When used as background, you need to manually set the value so you will need a different background each time. We can only make the color easy to change by using the SVG as mask;

    .box {
      display:inline-block;
      width:200px;
      position:relative;
    }
    
    .box:before {
      content:"";
      display:block;
      padding-top:100%;
    }
    
    .box::after {
      content:"";
      position:absolute;
      top:0;
      left:0;
      right:0;
      bottom:0;
      z-index:-1;
      background:var(--c,red);
      -webkit-mask:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-3 -3 106 106"><circle cx="50" cy="50" r="50" fill="transparent" stroke="black" stroke-width="5" style="stroke-dasharray:29.25, 10" /></svg>') center/contain;
              mask:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-3 -3 106 106"><circle cx="50" cy="50" r="50" fill="transparent" stroke="black" stroke-width="5" style="stroke-dasharray:29.25, 10" /></svg>') center/contain;
    }
    <div class="box">
    
    </div>
    
    <div class="box" style="width:150px;--c:linear-gradient(60deg,green 50%,yellow 0);">
    
    </div>
    
    <div class="box" style="width:100px;--c:linear-gradient(red,blue)">
    
    </div>

    0 讨论(0)
  • 2020-12-05 15:41

    Use stroke-dasharray with SVG.

    svg {
      width: 20vmax;
      height: 20vmax;
    }
    <svg viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="48" stroke-dasharray="10, 4" fill="transparent" stroke="purple" stroke-width="5" />
    </svg>

    Or you can use radial-gradient(), repeating-conic-gradient() functions without Firefox.

    .c {
      width: 20vmax;
      height: 20vmax;
      background-image: radial-gradient(#fff 68%, transparent 68% 70%, #fff 70%),
        repeating-conic-gradient(#000 0% 3%, transparent 3% 5%);
    }
    <div class="c"></div>

    0 讨论(0)
提交回复
热议问题