Hoe maak je een semi-cirkelvormige ringdiagram met CSS

Hoewel HTML5 Canvas en SVG mogelijk elegante oplossingen zijn voor het bouwen van diagrammen, zullen we in deze zelfstudie leren hoe we onze eigen ringdiagram kunnen bouwen met niets dan duidelijke CSS.

Om een ​​idee te krijgen van wat we gaan maken, bekijk de embedded CodePen-demo hieronder:

HTML-markup

We beginnen met een paar heel eenvoudige markeringen; een eenvoudige ongeordende lijst met een span element in elk van de lijstitems: 

  • CSS
  • HTML
  • PHP
  • Python

Stijlen aan de lijst toevoegen

Als de markup klaar is, passen we eerst een aantal basisstijlen toe op de ongeordende lijst:

.grafiek-vaardigheden positie: relatief; breedte: 350 px; hoogte: 175 px; 

Dan gaan we elke een geven ::na en een ::voor pseudo-element, en style ze:

.grafiekvaardigheden :: before, .chart-skills :: after position: absolute;  .chart-skills :: before content: "; width: inherit; height: inherit; border: 45px solid rgba (211,211,211, .3); border-bottom: none; border-top-left-radius: 175px; border -top-right-radius: 175px; .chart-skills :: after content: 'Topvaardigheden'; links: 50%; onder: 10px; transform: translateX (-50%); font-size: 1.1rem; lettertype: vet; kleur: cadetblue;

Besteed aandacht aan de stijlen voor de ::voor pseudo-element. Dit geeft ons onze halve cirkel.

Pseudo-elementen

Tot dusverre geven de bovengenoemde regels ons dit resultaat:

Stijlen aan de lijstitems toevoegen

Laten we nu de styling van de lijstitems bespreken.

positionering 

Met betrekking tot de positie van de lijstitems doen we het volgende:

  • Plaats ze precies onder hun ouder en
  • geef ze geschikte stijlen om een ​​omgekeerde halve cirkel te maken.

Verder zijn hier een aantal dingen vermeldenswaard:

  • De lijstitems zijn absoluut gepositioneerd, dus we kunnen hun instellen z-index eigendom.
  • We wijzigen de standaard transformatie-oorsprong eigenschapswaarde (d.w.z.. transformatie-oorsprong: 50% 50%) van de lijstitems. Concreet stellen we transformatie-oorsprong: 50% 0. Op deze manier, wanneer we de items animeren (roteren), wordt hun middelste bovenhoek het centrum van rotatie.

Dit zijn de bijbehorende CSS-stijlen:

.grafiekvaardigheden li positie: absoluut; top 100%; links: 0; width: inherit; hoogte: erven; rand: 45px massief; border-top: geen; grens-onder-links radius: 175 px; border-bottom-right-radius: 175px; transformatie-oorsprong: 50% 0;  .chart-vaardigheden li: nth-child (1) z-index: 4; randkleur: groen;  .chart-vaardigheden li: nth-child (2) z-index: 3; border-colour: firebrick;  .chart-vaardigheden li: nth-child (3) z-index: 2; randkleur: staalblauw;  .chart-vaardigheden li: nth-child (4) z-index: 1; randkleur: oranje; 

Bekijk wat we tot nu toe hebben gemaakt in de volgende visualisatie:

omspant en lijstitems

Momenteel is de enige lijstitem die zichtbaar is de groene (die heeft z-index: 4;) de anderen zijn eronder.

animaties

Voordat we de stappen voor het animeren van onze lijstitems bespreken, nemen we voor elk item het gewenste percentage op (dat wil zeggen: hoeveel van de donut elk zal dekken). Beschouw de volgende tabel:

Taal Percentage
CSS 12
HTML 32
PHP 34
Python 22

Vervolgens berekenen we hoeveel graden we hebben om elk item te animeren (roteren). Om het exacte aantal graden voor elk item te achterhalen, vermenigvuldigen we het percentage met 180 ° (geen 360 ° omdat we een a gebruiken halve cirkel ringdiagram):

Taal Percentage
Aantal graden
CSS 12 12/100 * 180 = 21,6
HTML 32
32/100 * 180 = 57,6
PHP 34 34/100 * 180 = 61,2
Python 22 22/100 * 180 = 39.6

Op dit moment zijn we klaar om de animaties in te stellen. Eerst definiëren we enkele animatiestijlen die over alle items worden gedeeld, door er enkele regels aan toe te voegen .grafiek-vaardigheden li:

 animatie-vulmodus: naar voren; animatie-duur: .4s; animatie-timing-functie: lineair; 

Vervolgens definiëren we de unieke animatiestijlen:

.grafiek-vaardigheden li: nth-child (1) z-index: 4; randkleur: groen; animatie-naam: rotate-one;  .chart-vaardigheden li: nth-child (2) z-index: 3; border-colour: firebrick; animatie-naam: rotate-two; animatie-vertraging: .4s;  .chart-vaardigheden li: nth-child (3) z-index: 2; randkleur: staalblauw; animatie-naam: rotate-three; animatie-vertraging: .8s;  .chart-vaardigheden li: nth-child (4) z-index: 1; randkleur: oranje; animatie-naam: rotate-four; animatie-vertraging: 1.2s; 

Merk op dat we een vertraging toevoegen aan alle items behalve de eerste. Op deze manier creëren we mooie sequentiële animaties. Wanneer de animatie van het eerste element bijvoorbeeld is voltooid, wordt het tweede element weergegeven, enzovoort. 

De volgende stap is om de daadwerkelijke animaties te specificeren:

@keyframes draaien-één 100% transform: rotate (21.6deg); / ** * 12% => 21.6deg * / @keyframes rotate-two 0% transform: rotate (21.6deg);  100% transform: rotate (79.2deg); / ** * 32% => 57.6deg * 57.6 + 21.6 => 79.2deg * / @keyframes rotate-three 0% transform: rotate (79.2deg);  100% transform: roteren (140.4deg); / ** * 34% => 61.2deg * 61.2 + 79.2 => 140.4deg * / @keyframes rotate-four 0% transform: rotate (140.4deg);  100% transformeren: roteren (180 graden); / ** * 22% => 39.6deg * 140.4 + 39.6 => 180deg * /

Voordat we verder gaan, bekijken we kort hoe de animaties werken:

Het eerste element komt uit transformeren: geen naar transformeren: roteren (21.6deg).

Het tweede element is afkomstig van transformeren: roteren (21.6deg)  (start vanaf de laatste positie van het eerste element) tot transformeren: roteren (79.2deg) (57.6deg + 21.6deg). 

Het derde element gaat van transformeren: roteren (79.2deg)  (start vanaf de laatste positie van het tweede element) tot transformeren: roteren (140.4deg) (61.2deg + 79.2deg).

Het vierde element is afkomstig van transformeren: roteren (140.4deg)  (start vanaf de laatste positie van het derde element) tot transformeren: roteren (180 graden) (140.4deg + 39.6deg).

Verbergen!

Last but not least, om de onderste helft van de grafiek te verbergen, moeten we de volgende regels toevoegen:

.grafiekvaardigheden / * bestaande regels ... * / overflow: verborgen;  .chart-skills li / * bestaande regels ... * / transform-style: preserverve-3d; backface-visibility: verborgen; 

De overloop verborgen eigenschapswaarde zorgt ervoor dat alleen de eerste halve cirkel (degene die is gemaakt met de ::voor pseudo-element) is zichtbaar. Voel je vrij om die eigenschap te verwijderen als je de beginpositie van de lijstitems wilt testen. 

De transformatiestijl: behouden-3d en achtervlak-visibility: hidden eigenschappen voorkomen flikkeringseffecten die kunnen optreden in verschillende browsers als gevolg van animaties. Als dit probleem nog steeds bestaat in uw browser, kunt u deze oplossingen ook proberen.

De kaart is bijna klaar! Het enige dat overblijft is om de diagramlabels vorm te geven, wat we in de volgende sectie zullen doen.

Hier is de CodePen-demo die het huidige uiterlijk van onze grafiek laat zien:

Stijlen toevoegen aan de labels

In dit gedeelte vormen we de kaartlabels.

positionering

Met betrekking tot hun positie doen we het volgende:

  • Geef hun positie: absoluut en gebruik de top en links eigenschappen om hun gewenste positie in te stellen.
  • Gebruik negatieve waarden om ze te roteren. Dit zijn natuurlijk geen willekeurige waarden. In feite worden deze uit het laatste frame van het bovenliggende item gehaald. Het laatste frame van het tweede lijstitem bevat bijvoorbeeld transformeren: roteren (79.2deg), en dus het gerelateerde label zal hebben transformeren: roteren (-79.2deg).

Hieronder staan ​​de bijbehorende CSS-stijlen:

.grafiek-vaardigheden overspanning positie: absoluut; font-size: .85rem;  .chart-vaardigheden li: nth-child (1) span top: 5px; links: 10px; transformeren: roteren (-21.6deg);  .chart-vaardigheden li: nth-child (2) span top: 20px; links: 10px; transformeren: roteren (-79.2deg);  .chart-vaardigheden li: nth-child (3) span top: 18px; links: 10px; transformeren: roteren (-140.4deg);  .chart-vaardigheden li: nth-child (4) span top: 10px; links: 10px; transformeren: roteren (-180 graden); 

animaties

Nu we de labels hebben gepositioneerd, is het tijd om ze te animeren. Twee dingen zijn het vermelden waard hier:

  • Standaard zijn alle labels verborgen en worden ze zichtbaar terwijl het bovenliggende item wordt geanimeerd. 
  • Net als bij de bovenliggende items gebruiken we de animatie-delay eigenschap om opeenvolgende animaties te maken. Daarnaast voegen we de achtervlak-visibility: hidden eigenschapswaarde om ervoor te zorgen dat er geen flikkerende effecten zijn als gevolg van animaties.

De CSS-regels die betrekking hebben op de animatie van de kaartlabels worden hieronder weergegeven:

.grafiek-vaardigheden overspannen backface-visibility: hidden; animatie: fade-in .4s lineair voorwaarts;  .chart-vaardigheden li: nth-child (2) span animation-delay: .4s;  .chart-vaardigheden li: nth-child (3) span animation-delay: .8s;  .chart-vaardigheden li: nth-child (4) span animation-delay: 1.2s;  @keyframes fade-in 0%, 90% dekking: 0;  100% dekking: 1; 

Dit is de laatste grafiek:

Browserondersteuning & problemen

Over het algemeen werkt de demo goed in alle browsers. Ik wil alleen twee kleine problemen bespreken die verband houden met de border-radius eigendom.

Ten eerste, als we onze artikelen verschillende kleuren zouden geven, zou de grafiek er ongeveer zo uit kunnen zien: 

Let bijvoorbeeld op de bovenste en onderste hoeken van het derde item. Er zijn twee rode lijnen die uit de randkleur van het vierde item komen. We kunnen die regels zien omdat het vierde item een ​​donkerdere randkleur heeft in vergelijking met de derde. Hoewel dit een klein probleem is, is het goed om je ervan bewust te zijn om de juiste kleuren voor je eigen grafieken te kiezen.

Ten tweede, in Safari ziet het diagram er als volgt uit:

Kijk naar de kleine openingen in de tweede en derde items. Als u iets weet over dit probleem, kunt u ons dit laten weten in de onderstaande opmerkingen!

Conclusie

In deze zelfstudie hebben we het proces doorlopen van het maken van een semi-cirkelvormige ringdiagram met pure CSS. Nogmaals, zoals vermeld in de inleiding, zijn er mogelijk krachtigere oplossingen (bijvoorbeeld HTML5 Canvas en SVG) om dit soort dingen te creëren. Als je echter iets eenvoudigs en lichtgewicht wilt bouwen en een uitdaging wilt, is CSS de juiste keuze!