Percent pie chart with css only

2019-01-29 13:50发布

问题:

I've found pretty nice "percent pie chart" and want to create it with CSS only. No animation is required. Just static "picture".

I understand If I wanna create this kind of chart I need to use elements like these

The questions are

  1. How to create element #2 ?
  2. How to manage shape of element #2 for smaller (5%) or higher percent (80%) values ?

回答1:

Using the new conic gradient, this can be managed with a single div which just landed in Chrome as an experimental property.

Image of Result

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

With thanks for Temani Afif it's possible to achieve this without the pseudo element using a border and leveraging 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>



回答2:

You can do this with multiple background.

From 0% to 50%:

.box {
  width: 100px;
  height: 100px;
  display: inline-block;
  border-radius: 50%;
  border: 5px solid transparent;
  background: 
    linear-gradient(#ccc, #ccc) padding-box, 
    linear-gradient(var(--v), #f2f2f2 50%, transparent 0) border-box,
    linear-gradient(to right, #f2f2f2 50%, blue 0) border-box;
}
<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>

From 50% to 100%:

.box {
  width:100px;
  height:100px;
  display:inline-block;
  border-radius:50%;
  border:5px solid transparent;
  background:
    linear-gradient(#ccc,#ccc) padding-box,
    linear-gradient(var(--v), blue 50%,transparent 0) border-box,
    linear-gradient(to right, #f2f2f2 50%,blue 0) border-box;
}
<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>

You can combine both like this:

.box {
  width:100px;
  height:100px;
  display:inline-block;
  border-radius:50%;
  border:5px solid transparent;
  background:
    linear-gradient(#ccc,#ccc) padding-box,
    linear-gradient(var(--v), #f2f2f2 50%,transparent 0) center/calc(var(--s)*100%) border-box,
    linear-gradient(var(--v), blue 50%,transparent 0) center/calc(100% - var(--s)*100%) border-box,
    linear-gradient(to right, #f2f2f2 50%,blue 0) border-box;
}
<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>