【问题标题】:How to create dashed circles with uniform spacing?如何创建具有均匀间距的虚线圆圈?
【发布时间】:2020-03-08 02:04:58
【问题描述】:

我想用 CSS 制作一个虚线圆圈,并通过以下过程创建它。

虽然这个过程可以显示虚线圆圈, 虚线的末端和起点之间的间隙变窄,并且间隙不均匀。

.c {
  width: 500px;
  height: 500px;
  border-width: 15px;
  border-style: dashed;
  border-radius: 600px;
}
<div class="c"></div>

有没有办法使间隙均匀?我们也可以控制破折号之间的间隙吗?

如果单独使用 CSS 无法做到这一点,我们正在考虑使用 JavaScript 或类似的东西。

【问题讨论】:

  • 就其价值而言,似乎只有 Chrome(和克隆,我猜)您的代码存在问题。
  • 是的。我觉得不错

标签: javascript html css


【解决方案1】:

这是conic-gradient() 解决方案的优化版本,您可以在其中轻松控制破折号的数量和间距

.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>

为了完全透明,我们考虑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>

为了让事情变得有趣,我们甚至可以考虑为破折号添加更复杂的颜色:

.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>

你可能肯定想要里面的一些内容,所以最好在伪元素上应用掩码/背景以避免掩盖内容:

.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>

获取更多 CSS 想法以实现类似结果的相关问题:CSS Only Pie Chart - How to add spacing/padding between slices?。您会发现比conic-gradient() 更多受支持的方式(实际上它不适用于Firefox),但您需要使用大量代码,而上述解决方案只需要一个元素。


使用 SVG 你还需要一些计算来确保你有一个统一的间距:

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>

使用 CSS 变量我们可以让它变得更简单,但并不是所有浏览器都支持它(实际上它在 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>

我们还可以轻松地使用 SVG 作为背景,让事情变得更加灵活:

.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>

当用作背景时,您需要手动设置值,因此每次都需要不同的背景。我们只能通过使用 SVG 作为遮罩来使颜色易于更改;

.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>

【讨论】:

  • 虽然这些方法很有趣,但在 Chrome 中看起来不错,但只有您的第一个基本 SVG 版本才能在 Firefox 中使用。值得注意的是,Firefox(甚至是 Nightly 版本)不支持 conic-gradient()repeating-conic-gradient()。因此,这些可能是未来可行的方法,但如果需要跨浏览器功能,目前还不能使用。
  • 鉴于问题 OP 的代码在 Firefox 中正常运行(即他们声明的问题在 Firefox 中不存在),但在 Chrome 中存在,探索至少两者之间的差异可能是个好主意Chrome(+ 克隆)和 Firefox,同时提供在两者中都可以使用的代码(或至少明确说明 now 可以使用的具有跨浏览器支持的代码)。
  • @Makyen 虽然 OP 代码在 Firefox 中运行良好,但我试图专注于 控制间隙 部分,因为使用基本边框我们无法控制间隙。我也添加了着色部分。我试图让它成为一个通用的答案。关于渐变,是的,Firefox 缺乏支持,但我很确定它很快就会出现(我仍然很惊讶他们在这方面迟到了,Chrome 近两年来一直支持这一点)。我链接到另一个问题以获得更多支持的方式,但它不是很明确。会更新的。
【解决方案2】:

stroke-dasharray 与 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>

或者您可以在没有 Firefox 的情况下使用 radial-gradient()repeating-conic-gradient() 函数。

.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%);
}
&lt;div class="c"&gt;&lt;/div&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    相关资源
    最近更新 更多