CSS Only Pie Chart - How to add spacing/padding between slices?

安稳与你 提交于 2019-12-02 02:28:52

问题


I've built a CSS only pie chart, but I need to add space between each slice almost as if it were a border. I've attempted to add a border to each slice but that doesn't actually work.

Any ideas on how to make this CSS pie chart look more like the following image?

Here is my code:

.palette {
  height: 48px;
  width: 48px;
}
.palette .colorOuter1,
.palette .colorOuter2,
.palette .colorOuter3,
.palette .colorOuter4,
.palette .colorOuter5 {
  height: 200px;
  width: 200px;
  border-radius: 50%;
  position: absolute;
  top: 0;
  left: 0;
  clip: rect(0px, 200px, 200px, 100px);
}
.palette .colorOuter1 {
  clip: auto;
  background: #eee;
}
.palette .colorOuter2 {
  transform: rotate(0deg);
}
.palette .colorOuter2 {
  transform: rotate(72deg);
}
.palette .colorOuter3 {
  transform: rotate(144deg);
}
.palette .colorOuter4 {
  transform: rotate(216deg);
}
.palette .colorOuter5 {
  transform: rotate(288deg);
}
.palette .colorInner1,
.palette .colorInner2,
.palette .colorInner3,
.palette .colorInner4,
.palette .colorInner5 {
  position: absolute;
  top: 0;
  left: 0;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  transform: rotate(72deg);
}
.palette .colorInner1 {
  background: #5D5E63;
  clip: rect(0px, 100px, 200px, 0px);
}
.palette .colorInner2 {
  background-color: #AEADA9;
  clip: rect(0px, 100px, 100px, 0px);
}
.palette .colorInner3 {
  background-color: #D5C4A8;
  clip: rect(0px, 100px, 100px, 0px);
}
.palette .colorInner4 {
  background-color: #AA875F;
  clip: rect(0px, 100px, 100px, 0px);
}
.palette .colorInner5 {
  background-color: #B7CBC7;
  clip: rect(0px, 100px, 100px, 0px);
}
.palette .centerOverlay {
  position: absolute;
  border-radius: 50%;
  top: 60px;
  left: 60px;
  background: #fff;
  width: 80px;
  height: 80px;
  display: block;
  clip: auto;
}
<div class="palette">
  <div class="colorOuter1">
    <div class="colorInner1"></div>
  </div>
  <div class="colorOuter2">
    <div class="colorInner2"></div>
  </div>
  <div class="colorOuter3">
    <div class="colorInner3"></div>
  </div>
  <div class="colorOuter4">
    <div class="colorInner4"></div>
  </div>
  <div class="colorOuter5">
    <div class="colorInner5"></div>
  </div>
  <div class="centerOverlay"></div>
</div>

回答1:


The way you are achieving the pie chart with CSS rotation and clipping makes it impossible to really know where the "border" actually is, and I don't think you can use border or clip-path to help much here (maybe clip-path and polygons, too difficult for me!)

You could place some more divs inside your .centerOverlay to act as more clipping masks, and then position them so that their midpoint is at exact center, rotate, and translate (not exactly fun, but). I've done two of them here as examples:

.palette {
  height: 48px;
  width: 48px;
  position:relative;
}
.palette .colorOuter1,
.palette .colorOuter2,
.palette .colorOuter3,
.palette .colorOuter4,
.palette .colorOuter5 {
  height: 200px;
  width: 200px;
  border-radius: 50%;
  position: absolute;
  top: 0;
  left: 0;
  clip: rect(0px, 200px, 200px, 100px);
}
.palette .colorOuter1 {
  clip: auto;
  background: #eee;
}
.palette .colorOuter2 {
  transform: rotate(0deg);
}
.palette .colorOuter2 {
  transform: rotate(72deg);
}
.palette .colorOuter3 {
  transform: rotate(144deg);
}
.palette .colorOuter4 {
  transform: rotate(216deg);
}
.palette .colorOuter5 {
  transform: rotate(288deg);
}
.palette .colorInner1,
.palette .colorInner2,
.palette .colorInner3,
.palette .colorInner4,
.palette .colorInner5 {
  position: absolute;
  top: 0;
  left: 0;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  transform: rotate(72deg);
}
.palette .colorInner1 {
  background: #5D5E63;
  clip: rect(0px, 100px, 200px, 0px);
}
.palette .colorInner2 {
  background-color: #AEADA9;
  clip: rect(0px, 100px, 100px, 0px);
}
.palette .colorInner3 {
  background-color: #D5C4A8;
  clip: rect(0px, 100px, 100px, 0px);
}
.palette .colorInner4 {
  background-color: #AA875F;
  clip: rect(0px, 100px, 100px, 0px);
}
.palette .colorInner5 {
  background-color: #B7CBC7;
  clip: rect(0px, 100px, 100px, 0px);
}
.palette .centerOverlay {
  position: absolute;
  border-radius: 50%;
  top: 60px;
  left: 60px;
  background: #fff;
  width: 80px;
  height: 80px;
  display: block;
  clip: auto;
}
.palette .north {
  position:absolute;
  top: -60px;
  left: 50%;
  background-color:white;
  width:4px;
  height:100px;

}
.palette .northeast {
  position:absolute;
  top: -10px;
  left: 50%;
  background-color:white;
  width:4px;
  height:100px;
  transform: rotate(72deg) translate(0px, -50px)

}
<div class="palette">
  <div class="colorOuter1">
    <div class="colorInner1"></div>
  </div>
  <div class="colorOuter2">
    <div class="colorInner2"></div>
  </div>
  <div class="colorOuter3">
    <div class="colorInner3"></div>
  </div>
  <div class="colorOuter4">
    <div class="colorInner4"></div>
  </div>
  <div class="colorOuter5">
    <div class="colorInner5"></div>
  </div>
  <div class="centerOverlay">
     <div class="north"></div>
     <div class="northeast"></div>
  </div>
  
</div>



回答2:


First I would recreate this with less of code relying on clip-path like below:

.palette {
  height: 200px;
  width: 200px;
  position:relative;
  overflow:hidden;
}
.palette > * {
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  border:50px solid var(--c,red);
  border-radius:50%;
  clip-path:polygon(50% 50%, 50% 0%, 100% 0%,100% 33.745%); 
}
.color1 {
  transform:rotate(72deg);
  --c:blue;
}
.color2 {
  transform:rotate(144deg);
  --c:orange;
}
.color3 {
  transform:rotate(-72deg);
  --c:green;
}
.color4 {
  transform:rotate(-144deg);
  --c:purple;
}
<div class="palette">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
</div>

Then you can apply a translation to your elements to create the gaps:

.palette {
  height: 200px;
  width: 200px;
  position:relative;
  margin:20px;
}
.palette > * {
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  border:50px solid var(--c,red);
  border-radius:50%;
  clip-path:polygon(50% 50%, 50% 0%, 100% 0%,100% 33.745%); 
}
.color1 {
  transform:rotate(72deg) translate(5px,-5px);
  --c:blue;
}
.color2 {
  transform:rotate(144deg) translate(5px,-5px);
  --c:orange;
}
.color3 {
  transform:rotate(-72deg) translate(5px,-5px);
  --c:green;
}
.color4 {
  transform:rotate(-144deg) translate(5px,-5px);
  --c:purple;
}
.color5 {
  transform:rotate(0) translate(5px,-5px);
  --c:red;
}
<div class="palette">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
</div>

Or if you want to create an effect of missing parts in order to keep the circular shape (like shown in your screenshot) you have to adjust the clip-path

.palette {
  height: 200px;
  width: 200px;
  position:relative;
  overflow:hidden;
}
.palette > * {
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  border:50px solid var(--c,red);
  border-radius:50%;
  clip-path:polygon(
    calc(50% + 5px) 50%, 
    calc(50% + 5px) 0%, 
    100% 0%,
    100% calc(33.745% - 5px),
    50% calc(50% - 5px)); 
}
.color1 {
  transform:rotate(72deg);
  --c:blue;
}
.color2 {
  transform:rotate(144deg);
  --c:orange;
}
.color3 {
  transform:rotate(-72deg);
  --c:green;
}
.color4 {
  transform:rotate(-144deg);
  --c:purple;
}
<div class="palette">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
</div>

And with CSS variables we can easily handle everything

.palette {
  --g:10px; /* The gap between shapes*/
  --s:50px; /* the size*/

  height: 200px;
  width: 200px;
  position:relative;
  display:inline-block;
  overflow:hidden;
}
.palette > * {
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  border:var(--s) solid var(--c,red);
  border-radius:50%;
  clip-path:polygon(
    calc(50% + var(--g)/2) 50%, 
    calc(50% + var(--g)/2) 0%, 
    100% 0%,
    100% calc(33.745% - var(--g)/2),
    50% calc(50% - var(--g)/2)); 
}
.color1 {
  transform:rotate(72deg);
  --c:blue;
}
.color2 {
  transform:rotate(144deg);
  --c:orange;
}
.color3 {
  transform:rotate(-72deg);
  --c:green;
}
.color4 {
  transform:rotate(-144deg);
  --c:purple;
}
<div class="palette">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
</div>

<div class="palette" style="--s:40px;--g:20px">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
</div>

<div class="palette" style="--s:60px;--g:0px">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
</div>

Using the same code you can easily scale to any number of slices:

With 8 slices:

.palette {
  --g:10px; /* The gap between shapes*/
  --s:50px; /* the size*/

  height: 200px;
  width: 200px;
  position:relative;
  display:inline-block;
  overflow:hidden;
}
.palette > * {
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  border:var(--s) solid var(--c,red);
  border-radius:50%;
  clip-path:polygon(
    calc(50% + var(--g)/2) 50%, 
    calc(50% + var(--g)/2) 0%, 
    100% 0%,
    100% calc(0% - var(--g)/2),
    50% calc(50% - var(--g)/2)); 
}
.color1 {
  transform:rotate(45deg); /* 360/8 */
  --c:blue;
}
.color2 {
  transform:rotate(90deg);
  --c:orange;
}
.color3 {
  transform:rotate(135deg);
  --c:green;
}
.color4 {
  transform:rotate(180deg);
  --c:purple;
}
.color5 {
  transform:rotate(-45deg); /* 360/8 */
  --c:orange;
}
.color6 {
  transform:rotate(-90deg);
  --c:lightblue;
}
.color7 {
  transform:rotate(-135deg);
  --c:pink;
}
<div class="palette">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
  <div class="color6"></div>
  <div class="color7"></div>
  <div class="color8"></div>
</div>

<div class="palette" style="--s:40px;--g:20px">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
  <div class="color6"></div>
  <div class="color7"></div>
  <div class="color8"></div>
</div>

<div class="palette" style="--s:60px;--g:0px">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
  <div class="color6"></div>
  <div class="color7"></div>
  <div class="color8"></div>
</div>

With 3 slices:

.palette {
  --g:10px; /* The gap between shapes*/
  --s:50px; /* the size*/

  height: 200px;
  width: 200px;
  position:relative;
  display:inline-block;
  overflow:hidden;
}
.palette > * {
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  border:var(--s) solid var(--c,red);
  border-radius:50%;
  clip-path:polygon(
    calc(50% + var(--g)/2) 50%, 
    calc(50% + var(--g)/2) 0%, 
    100% 0%,
    100% calc(78.665% - var(--g)/2),
    50% calc(50% - var(--g)/2)); 
}
.color1 {
  transform:rotate(120deg);
  --c:blue;
}
.color2 {
  transform:rotate(-120deg);
  --c:orange;
}
<div class="palette">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
</div>

<div class="palette" style="--s:40px;--g:20px">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
</div>

<div class="palette" style="--s:60px;--g:0px">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
</div>


Here is the formula behind the magic number used in the clip-path:

  • 5 slices: 33.75% = 50% - tan(90deg - 72deg)*50%
  • 8 slices: 0% = 50% - tan(90deg - 45deg)*50%
  • 3 slices: 78.665% = 50% - tan(90deg - 120deg)*50%

So the generic formula for N slices is 50%*(1 - tan(90deg - 360deg/N)) with N in [3 8]. If N < 3 we have trivial cases where we don't need a complex code. For N > 8 we need a different clip-path and a different formula: 50%*(1 + tan(360deg/N))

Example with 10 slices:

.palette {
  --g:10px; /* The gap between shapes*/
  --s:50px; /* the size*/

  height: 200px;
  width: 200px;
  position:relative;
  display:inline-block;
  overflow:hidden;
}
.palette > * {
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  border:var(--s) solid var(--c,red);
  border-radius:50%;
  clip-path:polygon(
    calc(50% + var(--g)/2) 50%, 
    calc(50% + var(--g)/2) 0%, 
    calc(86.327% - var(--g)/2) 0%,
    50% calc(50% - var(--g)/2)); 
}
.color1 {
  transform:rotate(36deg);
  --c:blue;
}
.color2 {
  transform:rotate(72deg);
  --c:orange;
}
.color3 {
  transform:rotate(108deg);
  --c:green;
}
.color4 {
  transform:rotate(144deg);
  --c:purple;
}
.color5 {
  transform:rotate(180deg);
  --c:lightblue;
}
.color6 {
  transform:rotate(-36deg);
  --c:silver;
}
.color7 {
  transform:rotate(-72deg);
  --c:black;
}
.color8 {
  transform:rotate(-108deg);
  --c:darkgreen;
}
.color9 {
  transform:rotate(-144deg);
  --c:pink;
}
<div class="palette">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
  <div class="color6"></div>
  <div class="color7"></div>
  <div class="color8"></div>
  <div class="color9"></div>
  <div class="color10"></div>
</div>

<div class="palette" style="--s:40px;--g:20px">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
  <div class="color6"></div>
  <div class="color7"></div>
  <div class="color8"></div>
  <div class="color9"></div>
  <div class="color10"></div>
</div>

<div class="palette" style="--s:60px;--g:0px">
  <div class="color1"></div>
  <div class="color2"></div>
  <div class="color3"></div>
  <div class="color4"></div>
  <div class="color5"></div>
  <div class="color6"></div>
  <div class="color7"></div>
  <div class="color8"></div>
  <div class="color9"></div>
  <div class="color10"></div>
</div>



来源:https://stackoverflow.com/questions/56797060/css-only-pie-chart-how-to-add-spacing-padding-between-slices

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!