Hur man bygger en halvcirkel Donut Diagram med CSS

Även om HTML5 Canvas och SVG kan vara mer eleganta lösningar för att bygga diagram, kommer vi att lära oss hur vi bygger vårt eget donut-diagram med ingenting annat än vanlig CSS.

För att få en uppfattning om vad vi ska skapa, ta en titt på den inbyggda CodePen-demo nedan:

HTML Markup

Vi börjar med en mycket grundläggande uppställning. en vanlig oorderad lista med a spänna element inuti var och en av listobjekten: 

  • CSS
  • html
  • PHP
  • Pytonorm

Lägger till stilar i listan

Med markeringen klar, tillämpar vi först några grundläggande stilar på den oordnade listan:

.diagramfärdigheter position: relativ; bredd: 350px; höjd: 175px; 

Då ska vi ge var och en en ::efter och a ::innan pseudo-element, och stil dem:

.diagram färdigheter :: före, .chart-färdigheter :: efter position: absolute;  .chart-färdigheter :: före innehåll: "; bredd: ärv, höjd: ärv, gräns: 45px fast rgba (211,211,211, .3), gränsbotten: ingen; gränsen till vänstra radien: 175px; Top-right-radius: 175px; .chart-skills :: efter innehåll: "Top Skills"; vänster: 50%; botten: 10px; transform: translateX (-50%); fontstorlek: 1,1rem; font-weight: bold; färg: cadetblue;

Var uppmärksam på stilar för ::innan pseudo-elementet. Detta ger oss vår halvcirkel.

Pseudoelement

Hittills ger ovannämnda regler oss detta resultat:

Lägga till stilar i listobjekten

Låt oss nu diskutera styling av listobjekten.

positionering 

Med avseende på listposternas ställning gör vi följande:

  • Placera dem rätt under deras förälder och
  • ge dem lämpliga stilar för att skapa en omvänd halvcirkel.

Dessutom är ett par saker värda att notera här:

  • Listobjekten är helt placerade, så vi kan ställa in deras z-index fast egendom.
  • Vi ändrar standardvärdet transform-ursprung fastighetsvärde (dvs.. transformations-ursprung: 50% 50%) i listobjekten. Specifikt bestämmer vi transformations-ursprung: 50% 0. På detta sätt, när vi animerar (roterar) föremålen, blir mitt mittövre hörn centrum för rotation.

Här är de associerade CSS-stilarna:

.diagramfärdigheter li position: absolute; topp 100%; vänster: 0; bredd: ärv höjd: ärv gräns: 45px solid; border-top: none; gränsen längst ner till vänster: 175px; gränsbotten-högra radie: 175px; transformations-ursprung: 50% 0;  .chart-skills li: nth-child (1) z-index: 4; gränsfärg: grön;  .chart-skills li: nth-child (2) z-index: 3; gränsfärg: firebrick;  .chart-skills li: nth-child (3) z-index: 2; gränsfärg: stålblå;  .chart-skills li: nth-child (4) z-index: 1; kantfärg: orange; 

Ta en titt på vad vi har byggt hittills i nästa visualisering:

spänner och listobjekt

För tillfället är det enda listobjektet som är synligt den gröna (som har z-index: 4;) de andra är under den.

animationer

Innan vi täcker stegen för att animera våra listobjekt, låt oss notera den önskade procentsatsen för varje objekt (dvs: hur mycket av munkningen kommer att täcka). Tänk på följande tabell:

Språk Procentsats
CSS 12
html 32
PHP 34
Pytonorm 22

Därefter beräknar vi hur många grader vi måste animera (rotera) var och en av objekten. För att ta reda på exakt antal grader för varje objekt multiplicerar vi sin procentandel med 180 ° (inte 360 ​​° eftersom vi använder en halvcirkel donut diagram):

Språk Procentsats
Antal grader
CSS 12 12/100 * 180 = 21,6
html 32
32/100 * 180 = 57,6
PHP 34 34/100 * 180 = 61,2
Pytonorm 22 22/100 * 180 = 39,6

Vid denna tidpunkt är vi redo att skapa animationerna. Först definierar vi några animationsstilar som delas över alla objekt, genom att lägga till några regler till .kartfärdigheter li:

 animations-fyll-läge: framåt; animeringstid: .4s; animation-timing-funktion: linjär; 

Då definierar vi de unika animationsstilarna:

.diagram färdigheter li: nth-child (1) z-index: 4; gränsfärg: grön; animationsnamn: rotera-en;  .chart-skills li: nth-child (2) z-index: 3; gränsfärg: firebrick; animationsnamn: rotera-två; animationsfördröjning: .4s;  .chart-skills li: nth-child (3) z-index: 2; gränsfärg: stålblå; animationsnamn: rotera-tre; animationsfördröjning: .8s;  .chart-skills li: nth-child (4) z-index: 1; kantfärg: orange; animationsnamn: rotera-fyra; animationsfördröjning: 1,2s; 

Observera att vi lägger till en fördröjning för alla artiklar utom den första. På detta sätt skapar vi trevliga sekventiella animeringar. Till exempel när animationen av det första elementet slutar visas det andra elementet och så vidare. 

Nästa steg är att ange de faktiska animationerna:

@keyframes rotera-en 100% transform: rotera (21.6deg); / ** * 12% => 21.6deg * / @keyframes rotera-två 0% transform: rotera (21.6deg);  100% transform: rotera (79,2deg); / ** * 32% => 57.6deg * 57.6 + 21.6 => 79.2deg * / @keyframes rotera-tre 0% transform: rotera (79.2deg);  100% transform: rotera (140,4deg); / ** * 34% => 61.2deg * 61.2 + 79.2 => 140.4deg * / @keyframes rotera-fyra 0% transform: rotera (140.4deg);  100% transform: rotera (180deg); / ** * 22% => 39.6deg * 140.4 + 39.6 => 180deg * /

Innan vi går längre tittar vi kort på hur animationerna fungerar:

Det första elementet går från transformera: ingen till transformera: rotera (21.6deg).

Det andra elementet går från transformera: rotera (21.6deg)  (börjar från det första elementets slutposition) till transformera: rotera (79.2deg) (57.6deg + 21.6deg). 

Det tredje elementet går från transformera: rotera (79.2deg)  (börjar från det sista läget för det andra elementet) till transformera: rotera (140.4deg) (61,2deg + 79,2deg).

Det fjärde elementet går från transformera: rotera (140.4deg)  (börjar från det tredje elementets slutposition) till transformera: rotera (180deg) (140.4deg + 39.6deg).

Dölj!

Sist men inte minst, för att dölja den nedre halvan av diagrammet måste vi lägga till följande regler:

.kartfärdigheter / * befintliga regler ... * / överfyllning: dold;  .chart-skills li / * befintliga regler ... * / transform-style: conserve-3d; backface-visibility: hidden; 

De överflöd: dold egendomsvärde säkerställer att endast den första halvcirkeln (den som skapats med ::innan pseudo-elementet) är synligt. Ta bort den här egenskapen om du vill testa den ursprungliga positionen för listobjekten. 

De transform-stil: bevara-3d och backface-visibility: hidden egenskaper förhindrar flimmer effekter som kan uppstå i olika webbläsare på grund av animeringar. Om problemet fortfarande finns i din webbläsare kan du också prova dessa lösningar.

Diagrammet är nästan klart! Allt som återstår är att ställa in tablettiketterna, som vi gör i nästa avsnitt.

Här är CodePen-demo som visar det aktuella utseendet på vårt diagram:

Lägger till stilar på etiketterna

I det här avsnittet kommer vi att ställa in diagrametiketterna.

positionering

Med hänsyn till deras ställning gör vi följande:

  • Ge dem position: absolut och använd topp och vänster egenskaper för att ställa in önskad position.
  • Använd negativa värden för att rotera dem. Naturligtvis är det inte slumpmässiga värden. Faktum är att dessa extraheras från den sista ramen för deras moderna objekt. Till exempel innehåller den sista ramen i det andra listobjektet transformera: rotera (79.2deg), och därmed dess relaterade etikett kommer att ha transformera: rotera (-79.2deg).

Nedan finns motsvarande CSS-stilar:

.diagram-kompetens span position: absolute; typsnittstorlek: .85rem;  .chart-skills li: nth-child (1) span top: 5px; vänster: 10px; transformera: rotera (-21.6deg);  .chart-skills li: nth-child (2) span top: 20px; vänster: 10px; transformera: rotera (-79.2deg);  .chart-skills li: nth-child (3) span top: 18px; vänster: 10px; transformera: rotera (-140,4deg);  .chart-skills li: nth-child (4) span top: 10px; vänster: 10px; transformera: rotera (-180deg); 

animationer

Nu när vi har placerat etiketterna är det dags att animera dem. Två saker är värda att nämna här:

  • Som standard är alla etiketter dolda och synliga eftersom deras ursprungliga objekt är animerat. 
  • På samma sätt som förälderobjekten använder vi animering-fördröjning egenskap för att skapa sekventiella animeringar. Dessutom lägger vi till backface-visibility: hidden egendom värde för att säkerställa att det inte finns några blinkande effekter på grund av animeringar.

CSS-reglerna som hanterar animeringen av diagrametiketterna visas nedan:

.diagram-kompetens span backface-visibility: hidden; animering: fade-in .4s linjär framåt;  .chart-skills li: nth-child (2) span animation-delay: .4s;  .chart-skills li: nth-child (3) span animation-delay: .8s;  .chart-skills li: nth-child (4) span animation-delay: 1.2s;  @keyframes fade-in 0%, 90% opacitet: 0;  100% opacitet: 1; 

Här är det slutliga diagrammet:

Webbläsarsupport och problem

Generellt fungerar demon bra i alla webbläsare. Jag vill bara diskutera två små problem som är relaterade till border-radius fast egendom.

Först, om vi skulle ge olika färger till våra föremål, kan diagrammet se ut så här: 

Lägg märke till till exempel den övre och nedre delen av det tredje objektet. Det finns två röda linjer som kommer från gränsfärgen på det fjärde objektet. Vi kan se dessa linjer eftersom det fjärde objektet har en mörkare kantfärg jämfört med den tredje. Även om det här är ett litet problem, är det bra att vara medveten om det för att välja lämpliga färger för dina egna diagram.

För det andra visas i Safari följande:

Titta på de små luckorna som visas i andra och tredje föremål. Om du vet något om detta problem, låt oss veta i kommentarerna nedan!

Slutsats

I denna handledning gick vi igenom processen med att skapa en halvcirkeln donut diagram med ren CSS. Återigen, som nämnts i introduktionen finns det potentiellt mer kraftfulla lösningar (t ex HTML5 Canvas och SVG) där ute för att skapa sådana slags saker. Men om du vill bygga något enkelt och lätt, och njut av en utmaning, är CSS vägen att gå!