【问题标题】:Percent pie chart with css only仅使用 css 的百分比饼图
【发布时间】:2018-09-06 13:39:38
【问题描述】:

我发现了一个非常不错的“百分比饼图”,并且只想用 CSS 来创建它。不需要动画。只是静态的“图片”。

我明白如果我想创建这种图表,我需要使用这些元素

问题是

  1. 如何创建元素 #2 ?
  2. 如何管理元素 #2 的形状以获得更小 (5%) 或更高百分比 (80%) 的值?

【问题讨论】:

  • 你没有提到这一点:除了 CSS,这应该只是 HTML 还是 SVG 也是一种选择?

标签: html css charts pie-chart


【解决方案1】:

2021 年新答案

通过一些现代技术,我们可以改进代码。你可以有圆边,也可以考虑动画:

@property --p{
  syntax: '<number>';
  inherits: true;
  initial-value: 1;
}

.pie {
  --p:20;      /* the percentage */
  --b:22px;    /* the thickness */
  --c:darkred; /* the color */
  --w:150px;   /* the size*/
  
  width:var(--w);
  aspect-ratio:1/1;
  position:relative;
  display:inline-grid;
  margin:5px;
  place-content:center;
  font-size:25px;
  font-weight:bold;
  font-family:sans-serif;
}
.pie:before,
.pie:after {
  content:"";
  position:absolute;
  border-radius:50%;
}
.pie:before {
  inset:0;
  background:
    radial-gradient(farthest-side,var(--c) 98%,#0000) top/var(--b) var(--b) no-repeat,
    conic-gradient(var(--c) calc(var(--p)*1%),#0000 0);
  -webkit-mask:radial-gradient(farthest-side,#0000 calc(99% - var(--b)),#000 calc(100% - var(--b)));
          mask:radial-gradient(farthest-side,#0000 calc(99% - var(--b)),#000 calc(100% - var(--b)));
}
.pie:after {
  inset:calc(50% - var(--b)/2);
  background:var(--c);
  transform:rotate(calc(var(--p)*3.6deg - 90deg)) translate(calc(var(--w)/2 - 50%));
}
.animate {
  animation:p 1s .5s both;
}
.no-round:before {
  background-size:0 0,auto;
}
.no-round:after {
  content:none;
}
@keyframes p{
  from{--p:0;}
}

body {
  background:#ddd;
}
<div class="pie" style="--p:20"> 20%</div>
<div class="pie" style="--p:40;--c:darkblue;--b:10px"> 40%</div>
<div class="pie no-round" style="--p:60;--c:purple;--b:15px"> 60%</div>
<div class="pie animate" style="--p:80;--c:orange;"> 80%</div>
<div class="pie animate no-round" style="--p:90;--c:lightgreen"> 90%</div>

旧答案

您可以在多个背景下执行此操作。

0%50%

.box {
  width: 100px;
  height: 100px;
  display: inline-block;
  border-radius: 50%;
  padding: 5px;
  background: 
    linear-gradient(#ccc, #ccc) content-box, 
    linear-gradient(var(--v), #f2f2f2 50%, transparent 0),
    linear-gradient(to right, #f2f2f2 50%, blue 0);
}
<div class="box" style="--v:-90deg"></div><!-- 0% -->
<div class="box" style="--v:-45deg"></div><!-- 12.5% -->
<div class="box" style="--v:  0deg"></div><!-- 25% -->
<div class="box" style="--v: 45deg"></div><!-- 37.5% -->
<div class="box" style="--v: 90deg"></div><!-- 50% -->

<p>The formula is [p = (18/5) * x - 90]. <small>Where x is the percentage and p the degree</small></p>
<p>for x = 5% --> p = -72deg </p>
<div class="box" style="--v:-72deg"></div>

50%100%

.box {
  width:100px;
  height:100px;
  display:inline-block;
  border-radius:50%;
  padding:5px;
  background:
    linear-gradient(#ccc,#ccc) content-box,
    linear-gradient(var(--v), blue 50%,transparent 0),
    linear-gradient(to right, #f2f2f2 50%,blue 0);
}
<div class="box" style="--v:-90deg"></div><!-- 50% -->
<div class="box" style="--v:-45deg"></div><!-- 62.5% -->
<div class="box" style="--v:  0deg"></div><!-- 75% -->
<div class="box" style="--v: 45deg"></div><!-- 87.5% -->
<div class="box" style="--v: 90deg"></div><!-- 100% -->

<p>The formula is [p = (18/5) * x - 270]. <small>Where x is the percentage and p the degree</small></p>
<p>for x = 80% --> p = 18deg </p>
<div class="box" style="--v:18deg"></div>

您可以像这样将两者结合起来:

.box {
  width:100px;
  height:100px;
  display:inline-block;
  border-radius:50%;
  padding:5px;
  background:
    linear-gradient(#ccc,#ccc) content-box,
    linear-gradient(var(--v), #f2f2f2 50%,transparent 0) 0/calc(var(--s)*100%)      ,
    linear-gradient(var(--v), blue    50%,transparent 0) 0/calc((1 - var(--s))*100%),
    linear-gradient(to right, #f2f2f2 50%,blue 0);
}
<div class="box" style="--v:-90deg;--s:1"></div>
<div class="box" style="--v:0deg;--s:1"></div>
<div class="box" style="--v:90deg;--s:1"></div>
<div class="box" style="--v:0deg;--s:0"></div>
<div class="box" style="--v:90deg;--s:0"></div>

现在我们可以像下面这样优化以考虑百分比值:

.box {
  
  --v:calc( ((18/5) * var(--p) - 90)*1deg);

  width:100px;
  height:100px;
  display:inline-block;
  border-radius:50%;
  padding:10px;
  background:
    linear-gradient(#ccc,#ccc) content-box,
    linear-gradient(var(--v), #f2f2f2     50%,transparent 0) 0/min(100%,(50 - var(--p))*100%),
    linear-gradient(var(--v), transparent 50%,blue        0) 0/min(100%,(var(--p) - 50)*100%),
    linear-gradient(to right, #f2f2f2 50%,blue 0);
}
<div class="box" style="--p:5;"></div>
<div class="box" style="--p:20;"></div>
<div class="box" style="--p:50;"></div>
<div class="box" style="--p:60;"></div>
<div class="box" style="--p:75;"></div>
<div class="box" style="--p:100;"></div>

获取另一个版本的相关问题:Creating a static pie chart with CSS


我们也可以考虑mask增加透明度:

.box {
  
  --v:calc( ((18/5) * var(--p) - 90)*1deg);

  width:100px;
  height:100px;
  display:inline-block;
  border-radius:50%;
  padding:10px;
  background:
    linear-gradient(var(--v), #f2f2f2     50%,transparent 0) 0/min(100%,(50 - var(--p))*100%),
    linear-gradient(var(--v), transparent 50%,blue        0) 0/min(100%,(var(--p) - 50)*100%),
    linear-gradient(to right, #f2f2f2 50%,blue 0);
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite:destination-out;
  mask-composite:exclude;
}

body {
  background:linear-gradient(to right,red,yellow);
}
<div class="box" style="--p:5;"></div>
<div class="box" style="--p:20;"></div>
<div class="box" style="--p:50;"></div>
<div class="box" style="--p:60;"></div>
<div class="box" style="--p:75;"></div>
<div class="box" style="--p:100;"></div>

也像下面这样:

.box {
  
  --v:calc( ((18/5) * var(--p) - 90)*1deg);

  width:100px;
  height:100px;
  display:inline-block;
  border-radius:50%;
  padding:10px;
  background:
    linear-gradient(var(--v), transparent 50%,blue        0) 0/min(100%,(var(--p) - 50)*100%),
    linear-gradient(to right, transparent 50%,blue 0);
  -webkit-mask:
    linear-gradient(var(--v), #f2f2f2     50%,transparent 0) 0/min(100%,(50 - var(--p))*100%),
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite:destination-out;
  mask-composite:exclude;
}

body {
  background:linear-gradient(to right,red,yellow);
}
<div class="box" style="--p:5;"></div>
<div class="box" style="--p:20;"></div>
<div class="box" style="--p:50;"></div>
<div class="box" style="--p:60;"></div>
<div class="box" style="--p:75;"></div>
<div class="box" style="--p:100;"></div>

相关:Border Gradient with Border Radius

【讨论】:

  • 谢谢,看起来不错。但是如何使用 2 种颜色呢?例如,蓝色表示已使用,灰色表示未使用,如第一张图片所示?
  • @VicVKh 只需将白色 (#fff) 替换为任何颜色
  • 非常感谢,这正是我所需要的。
  • 如果是每 25% 的步长,边框颜色是完全有效的 ;)
  • @G-Cyr 我用公式进行编辑以使其更清晰;)
【解决方案2】:

使用新的 conic gradient,这可以通过一个 div 进行管理,该 div 刚刚作为实验属性登陆 Chrome。

结果图片

:root {
  --size: 100px;
  --bord: 10px;
}

.chart {
  width: var(--size);
  height: var(--size);
  margin: 1em auto;
  border-radius: 50%;
  background-image: conic-gradient(lightseagreen var(--value), lightgrey var(--value));
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
}

.chart::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: calc(100% - var(--bord));
  height: calc(100% - var(--bord));
  background: white;
  border-radius: inherit;
}

p {
  position: relative;
  z-index: 1;
  font-size: 2em;
}

.x-60 {
  --value: 60%;
}

.x-20 {
  --value: 20%;
}
<div class="chart x-60">
  <p>60%</p>
</div>

<div class="chart x-20">
  <p>20%</p>
</div>

感谢 Temani Afif,无需使用边框的伪元素并利用 background-clip...

 background: 
    linear-gradient(white,white) padding-box,
    conic-gradient(lightseagreen var(--value), lightgrey var(--value)) border-box;

:root {
  --size: 100px;
  --bord: 10px;
}

.chart {
  width: var(--size);
  height: var(--size);
  margin: 1em auto;
  border: var(--bord) solid transparent;
  border-radius: 50%;
  background: linear-gradient(white, white) padding-box, conic-gradient(lightseagreen var(--value), lightgrey var(--value)) border-box;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 2em;
}

.x-60 {
  --value: 60%;
}

.x-20 {
  --value: 20%;
}
<div class="chart x-60">
  <p>60%</p>
</div>

<div class="chart x-20">
  <p>20%</p>
</div>

【讨论】:

    【解决方案3】:

    嘿,你可以添加小的 CSS 样式

    .circle {
      position: relative;
      top: 5px;
      left: 5px;
      text-align: center;
      width: 100px;
      height: 100px;
      border-radius: 100%;
      background-color: #ffffff;
    }
    
    .circle-border {
      position: relative;
      text-align: center;
      width: 110px;
      height: 110px;
      margin-left: 30%;
      border-radius: 100%;
      background-color: #E53B3B;
      background: linear-gradient(0deg, lightgray 100%, black 0%)
    }
    

    HTML

    <div class="circle-border" id="circleElement">
      <div class="circle" id="circleElementValue">
        aaa
      </div>
    </div>
    

    JS : 自动显示填充百分比

    // let i = 75;
    //   let deg=Math.round(1.8*i); 
    //   let completed=0;
    //   let remaining=100-i;
    //   // completed = (remaining>50)? 50 : completed;
    // let backgroundStlye = 'linear-gradient('+deg+'deg, lightgray '+remaining +'%, black '+completed + '%)';
    //   setTimeout(function(){
    //     console.log(backgroundStlye);
    //   document.getElementById("circleElement").style.background =backgroundStlye;
    // },i*100);
    
    for(let i=1;i<=100;i++){
      let deg=Math.round(1.8*i); 
      let completed=i;
      let remaining=100-i;
      completed = (remaining<50)? 0 : completed;
    let backgroundStlye = 'linear-gradient('+deg+'deg, lightgray '+remaining +'%, black '+completed + '%)';
      setTimeout(function(){
        console.log(backgroundStlye);
      document.getElementById("circleElement").style.background =backgroundStlye;
        document.getElementById("circleElementValue").innerHTML = i+'%';
    },i*100);
    }
    

    我创建了示例https://codepen.io/arun-b-shet/pen/mdVVWXo

    希望你喜欢yyyyyyyyyyy

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多