Author: | Jerry Low |
---|---|
Views Total: | 13,491 views |
Official Page: | Go to website |
Last Update: | May 6, 2020 |
License: | MIT |
Preview:

Description:
A minimal clean donut chart to represent percentage values as slices using pure CSS/SCSS.
How to use it:
1. Create the HTML for the donut chart and define the percentage value for each slice using CSS variables as follows:
<div class="donut" style="--first: .40; --second: .33; --third: .12; --fourth: .08; --fifth: 0.07"> <div class="donut__slice donut__slice__first"></div> <div class="donut__slice donut__slice__second"></div> <div class="donut__slice donut__slice__third"></div> <div class="donut__slice donut__slice__fourth"></div> <div class="donut__slice donut__slice__fifth"></div> <div class="donut__label"> <div class="donut__label__heading"> CSSScript.Com </div> <div class="donut__label__sub"> Donut Chart </div> </div> </div>
2. The main CSS styles for the donut chart. Feel free to override the CSS styles as shown below:
.donut { --donut-size: 300px; --donut-border-width: 20px; --donut-spacing: 0; --donut-spacing-color: 255, 255, 255; --donut-spacing-deg: calc(1deg * var(--donut-spacing)); border-radius: 50%; height: var(--donut-size); margin: 40px; position: relative; width: var(--donut-size); } .donut__label { left: 50%; line-height: 1.5; position: absolute; text-align: center; top: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); width: 80%; } .donut__label__heading { font-size: 24px; font-weight: 600; } .donut__label__sub { color: #666666; font-size: 14px; letter-spacing: 0.05em; } .donut__slice { height: 100%; position: absolute; width: 100%; } .donut__slice::before, .donut__slice::after { border: var(--donut-border-width) solid rgba(0, 0, 0, 0); border-radius: 50%; content: ''; height: 100%; left: 0; position: absolute; top: 0; -webkit-transform: rotate(45deg); transform: rotate(45deg); width: 100%; } .donut__slice::before { border-width: calc(var(--donut-border-width) + 1px); box-shadow: 0 0 1px 0 rgba(var(--donut-spacing-color), calc(100 * var(--donut-spacing))); } .donut__slice__first { --first-start: 0; } .donut__slice__first::before { border-top-color: rgba(var(--donut-spacing-color), calc(100 * var(--donut-spacing))); -webkit-transform: rotate(calc(360deg * var(--first-start) + 45deg)); transform: rotate(calc(360deg * var(--first-start) + 45deg)); } .donut__slice__first::after { border-top-color: #ff6838; border-right-color: rgba(255, 104, 56, calc(100 * (var(--first) - .25))); border-bottom-color: rgba(255, 104, 56, calc(100 * (var(--first) - .5))); border-left-color: rgba(255, 104, 56, calc(100 * (var(--first) - .75))); -webkit-transform: rotate(calc(360deg * var(--first-start) + 45deg + var(--donut-spacing-deg))); transform: rotate(calc(360deg * var(--first-start) + 45deg + var(--donut-spacing-deg))); } .donut__slice__second { --second-start: calc(var(--first)); --second-check: max(calc(var(--second-start) - .5), 0); -webkit-clip-path: inset(0 calc(50% * (var(--second-check) / var(--second-check))) 0 0); clip-path: inset(0 calc(50% * (var(--second-check) / var(--second-check))) 0 0); } .donut__slice__second::before { border-top-color: rgba(var(--donut-spacing-color), calc(100 * var(--donut-spacing))); -webkit-transform: rotate(calc(360deg * var(--second-start) + 45deg)); transform: rotate(calc(360deg * var(--second-start) + 45deg)); } .donut__slice__second::after { border-top-color: #ffc820; border-right-color: rgba(255, 200, 32, calc(100 * (var(--second) - .25))); border-bottom-color: rgba(255, 200, 32, calc(100 * (var(--second) - .5))); border-left-color: rgba(255, 200, 32, calc(100 * (var(--second) - .75))); -webkit-transform: rotate(calc(360deg * var(--second-start) + 45deg + var(--donut-spacing-deg))); transform: rotate(calc(360deg * var(--second-start) + 45deg + var(--donut-spacing-deg))); } .donut__slice__third { --third-start: calc(var(--first) + var(--second)); --third-check: max(calc(var(--third-start) - .5), 0); -webkit-clip-path: inset(0 calc(50% * (var(--third-check) / var(--third-check))) 0 0); clip-path: inset(0 calc(50% * (var(--third-check) / var(--third-check))) 0 0); } .donut__slice__third::before { border-top-color: rgba(var(--donut-spacing-color), calc(100 * var(--donut-spacing))); -webkit-transform: rotate(calc(360deg * var(--third-start) + 45deg)); transform: rotate(calc(360deg * var(--third-start) + 45deg)); } .donut__slice__third::after { border-top-color: #97c95c; border-right-color: rgba(151, 201, 92, calc(100 * (var(--third) - .25))); border-bottom-color: rgba(151, 201, 92, calc(100 * (var(--third) - .5))); border-left-color: rgba(151, 201, 92, calc(100 * (var(--third) - .75))); -webkit-transform: rotate(calc(360deg * var(--third-start) + 45deg + var(--donut-spacing-deg))); transform: rotate(calc(360deg * var(--third-start) + 45deg + var(--donut-spacing-deg))); } .donut__slice__fourth { --fourth-start: calc(var(--first) + var(--second) + var(--third)); --fourth-check: max(calc(var(--fourth-start) - .5), 0); -webkit-clip-path: inset(0 calc(50% * (var(--fourth-check) / var(--fourth-check))) 0 0); clip-path: inset(0 calc(50% * (var(--fourth-check) / var(--fourth-check))) 0 0); } .donut__slice__fourth::before { border-top-color: rgba(var(--donut-spacing-color), calc(100 * var(--donut-spacing))); -webkit-transform: rotate(calc(360deg * var(--fourth-start) + 45deg)); transform: rotate(calc(360deg * var(--fourth-start) + 45deg)); } .donut__slice__fourth::after { border-top-color: #1cb2f6; border-right-color: rgba(28, 178, 246, calc(100 * (var(--fourth) - .25))); border-bottom-color: rgba(28, 178, 246, calc(100 * (var(--fourth) - .5))); border-left-color: rgba(28, 178, 246, calc(100 * (var(--fourth) - .75))); -webkit-transform: rotate(calc(360deg * var(--fourth-start) + 45deg + var(--donut-spacing-deg))); transform: rotate(calc(360deg * var(--fourth-start) + 45deg + var(--donut-spacing-deg))); } .donut__slice__fifth { --fifth-start: calc(var(--first) + var(--second) + var(--third) + var(--fourth)); --fifth-check: max(calc(var(--fifth-start) - .5), 0); -webkit-clip-path: inset(0 calc(50% * (var(--fifth-check) / var(--fifth-check))) 0 0); clip-path: inset(0 calc(50% * (var(--fifth-check) / var(--fifth-check))) 0 0); } .donut__slice__fifth::before { border-top-color: rgba(var(--donut-spacing-color), calc(100 * var(--donut-spacing))); -webkit-transform: rotate(calc(360deg * var(--fifth-start) + 45deg)); transform: rotate(calc(360deg * var(--fifth-start) + 45deg)); } .donut__slice__fifth::after { border-top-color: #1685b8; border-right-color: rgba(22, 133, 184, calc(100 * (var(--fifth) - .25))); border-bottom-color: rgba(22, 133, 184, calc(100 * (var(--fifth) - .5))); border-left-color: rgba(22, 133, 184, calc(100 * (var(--fifth) - .75))); -webkit-transform: rotate(calc(360deg * var(--fifth-start) + 45deg + var(--donut-spacing-deg))); transform: rotate(calc(360deg * var(--fifth-start) + 45deg + var(--donut-spacing-deg))); }
Very helpful. A quick question: How could you add labels to each slice. Thanks!!
It has a bug when you use 3 colors and use value 0.3 / 0.6 / 0.1
If you place 0.6 first and the smaller numbers after, it is working. I also ran into the issue when the first slice is not the largest number it is incorrect. So it is taking away bits from the end instead of the beginning
This code seems perfect! But is there any way to do a click or hover event on the individual pieces and not the whole circle?