Ein Balkendiagramm mit CSS Grid erstellen

Avatar of Robin Rendle
Robin Rendle am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Hinweis der Redaktion: Dieser Beitrag ist nur ein Experiment, um mit neuen CSS-Eigenschaften zu spielen. Der untenstehende Code sollte daher nicht ohne ernsthafte Verbesserungen der Barrierefreiheit verwendet werden.

Ich habe eine eigenartige Obsession mit Diagrammen und aus irgendeinem Grund möchte ich herausfinden, auf alle möglichen Arten, sie mit CSS zu erstellen. Ich schätze, das hat zwei Gründe. Erstens finde ich es interessant, dass es unzählige Möglichkeiten gibt, Diagramme und Daten im Web zu gestalten. Zweitens ist es großartig, um neue und unbekannte Technologien zu lernen. In diesem Fall: CSS Grid!

Diese Diagramm-Obsession brachte mich also zum Nachdenken: Wie würde man ein ganz normales, responsives Balkendiagramm mit CSS Grid erstellen, so etwas wie dieses?

Schauen wir uns an, wie ich dorthin gelangt bin!

Der schnelle und einfache Ansatz

Da Grid auf den ersten Blick verwirrend und seltsam sein kann, konzentrieren wir uns zunächst darauf, einen wirklich provisorischen Prototyp zu erstellen. Um loszulegen, benötigen wir die Markup für unser Diagramm

<div class="chart">
  <div class="bar-1"></div>
  <div class="bar-2"></div>
  <div class="bar-3"></div>
  <div class="bar-4"></div>
  <!--  all the way up to bar-12 -->
</div>

Jede dieser bar- Klassen wird einen ganzen Balken in unserem Diagramm ausmachen und, so übel das auch erscheinen mag, wir werden uns vorerst keine Sorgen um Semantik oder Beschriftungen des Grids oder der Daten machen. Das kommt später – konzentrieren wir uns auf das CSS, damit wir mehr über Grid lernen.

Okay, damit können wir jetzt mit dem Styling beginnen! Wir benötigen 12 Balken in unserem Diagramm mit einem Abstand von 5 Pixeln dazwischen, also können wir unserer Elternklasse .chart die entsprechenden CSS Grid-Eigenschaften zuweisen

.chart {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-column-gap: 5px;
}

Das ist ziemlich geradlinig, wenn Sie mit Grid vertraut sind, aber es beschreibt effektiv: „Ich möchte 12 Spalten, wobei jedes der Kindelemente eine gleiche Breite (1 Fraktion) mit einem Abstand von 5 Pixeln dazwischen hat“.

Aber jetzt kommt der knifflige Teil: Mit Grid können wir die grid-template-rows-Eigenschaft verwenden, um die Höhe jedes unserer Diagrammbalken festzulegen

.chart {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-template-rows: repeat(100, 1fr);
  grid-column-gap: 5px;
}

Wir können diese nette neue Eigenschaft verwenden, um 100 Zeilen in unserem Grid zu erstellen, und so können wir jeden unserer Balken auf einen Prozentsatz dieser Höhe setzen und die Rechnung wird für uns einfach. Wieder verwenden wir diese repeat()-Funktion, damit jede unserer Zeilen die gleiche Höhe hat.

Bevor ich das alles im Detail erkläre, geben wir unserem Diagramm eine maximale Breite und zentrieren es mit Flexbox

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background-color: #eee;
  display: flex;
  justify-content: center;
}

.chart {
  height: 100vh;
  width: 70vw;
  /* other chart styles go here */
}

An diesem Punkt ist unser Diagramm noch leer, da wir unseren Kindelementen noch keinen Platz im Grid zugewiesen haben. Also beheben wir das! Wir wählen jede Klasse aus, die bar enthält, und verwenden die Eigenschaften grid-row-start und grid-row-end, damit sie den vertikalen Raum im Grid ausfüllen. Später werden wir eine dieser Eigenschaften ändern, um die benutzerdefinierte Höhe jedes Balkens zu definieren.

[class*="bar"] {
  grid-row-start: 1;
  grid-row-end: 101;
  border-radius: 5px 5px 0 0;
  background-color: #ff4136;
}

Wenn Sie also von diesen grid-row-Eigenschaften verwirrt sind, ist das in Ordnung! Wir sagen jedem unserer Balken, dass er ganz oben im Grid (1) beginnen und ganz unten (101) enden soll. Aber warum verwenden wir 101 als Wert für diese Eigenschaft, wenn wir unserem Grid nur 100 Zeilen zugewiesen haben? Lassen Sie uns das kurz untersuchen, bevor wir weitermachen!

Grid-Linien

Eine der eigentümlichen Dinge an Grid, die ich vor dieser Demo nicht bedacht hatte, war das Konzept der Grid-Linien, was für das Verständnis dieses neuen Layout-Tools super wichtig ist. Hier ist eine Veranschaulichung, wie Grid-Linien in einem Raster mit vier Spalten und vier Zeilen gezeichnet werden

Dieses neue Beispiel enthält vier Spalten und vier Zeilen mit den folgenden Stilen

.grid {
  grid-gap: 5px;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
}

.special-col {
  grid-row: 2 / 4;
  background-color: #222;
}

grid-row ist eine Kurzschreibweise für grid-row-start und grid-row-end, wobei der erste Wert angibt, wo das Element im Grid beginnen soll, und der letzte Wert, wo es enden soll. Aber! Das bedeutet, dass wir möchten, dass dieses spezielle Element hier an der Grid-Linie 2 beginnt und an der Grid-Linie 4 endet – nicht am Ende von Zeile 4. Wenn wir möchten, dass die schwarze Box alle 4 Zeilen ausfüllt, müsste sie an Linie 5 enden oder grid-row: 2 / 5, was, wenn man darüber nachdenkt, sehr viel Sinn ergibt.

Anders ausgedrückt: Wir sollten nicht davon ausgehen, dass Elemente ganze Zeilen oder Spalten in einem Grid einnehmen, sondern nur zwischen diesen Grid-Linien verlaufen. Das hat mich eine Weile gebraucht, um es konzeptionell zu verstehen und mich daran zu gewöhnen, nachdem ich einem aktuellen Tutorial von Jen Simmons dazu durchgearbeitet hatte.

Jedenfalls!

Zurück zur Demo

Das ist also der Grund, warum wir in unserer Diagramm-Demo alle Spalten an Linie 101 und nicht an 100 enden lassen – weil wir möchten, dass sie die letzte Zeile (100) ausfüllen, also müssen wir sie zu dieser bestimmten Grid-Linie (101) schicken.

Da unsere .chart-Klasse vw/vh-Einheiten verwendet, haben wir auch ein schön responsives Diagramm, ohne viel Arbeit investieren zu müssen. Wenn Sie die unten stehende Grafik vergrößern/verkleinern, werden Sie feststellen, dass sie sich gut anpasst oder dehnt, um immer den gesamten Viewport einzunehmen.

Von hier aus können wir beginnen, jeden einzelnen Balken zu stylen, um ihm die richtigen Daten zu geben, und es gibt eine ganze Reihe verschiedener Möglichkeiten, dies zu tun. Sehen wir uns nur eine davon an.

Stellen wir uns zunächst vor, wir möchten, dass der erste Balken in unserem Diagramm, .bar-1, 50/100 oder die halbe Höhe des Diagramms ist. Wir könnten das folgende CSS schreiben und wären fertig.

[class*="bar"] {
  grid-row-end: 101;
}

.bar-1 {
  grid-row-start: 50;
}

Das sieht gut aus! Aber hier ist der Haken – was wir eigentlich mit grid-row-start deklarieren, ist, dass der Balken bei „50“ beginnt und bei „101“ endet, aber das ist nicht wirklich das, was wir wollen. Hier ist ein Beispiel: Nehmen wir an, die Daten ändern sich in diesem hypothetischen Beispiel und wir müssen jetzt 20/100 sein. Gehen wir zurück und ändern den Wert.

.bar-1 {
  grid-row-start: 20;
}

Das ist nicht richtig! Wir möchten nicht, dass der Balken im Grid bei 30 beginnt, sondern 30 % der Höhe des Diagramms beträgt. Wir könnten unseren Wert auf grid-row-start: 20; ändern oder stattdessen die Eigenschaft grid-row-end verwenden, richtig? Nun, nicht ganz.

.bar-1 {
  grid-row-end: 20;
}

Die Größe des Balkens ist korrekt, aber die Position ist falsch, weil wir dem Balken sagen, dass er bei 30/100 enden soll. Wie beheben wir das und machen unseren Code super lesbar? Nun, ein Ansatz ist, Sass die Mathematik für uns erledigen zu lassen. Idealerweise möchten wir Folgendes schreiben:

.bar-1 {
  // makes a bar that's 60/100 and positioned at the bottom of our chart
  @include chartValue(60);
}

Und egal welchen Wert wir in dieses Mixin eingeben, wir wollen immer die korrekte Höhe und Position des Diagramms im Grid erhalten. Die Mathematik, die dieses Mixin antreibt, ist eigentlich ziemlich einfach: Wir müssen nur unseren Wert nehmen, ihn von der Gesamtzahl der Zeilen abziehen und ihn dann an die Eigenschaft grid-row-start anhängen, so:

@mixin chartValue($data) {
  $totalRows: 101;
  $result: $totalRows - $data;
  grid-row-start: $result;
}

.bar-1 {
  @include chartValue(20);
}

Der endgültige Wert, der von unserem Sass-Mixin ausgegeben wird, ist also grid-row-start: 81, aber unser Code ist super lesbar! Wir müssen nicht einmal unser Grid ansehen, um zu wissen, was passieren wird – das Diagrammelement wird am unteren Rand des Grids positioniert und der Wert ist immer korrekt.

Wie erstellen wir all diese Grid-Klassen? Ich denke, ein guter Ansatz ist, Sass einfach all diese Klassen automatisch für uns generieren zu lassen. Mit einer kleinen Änderung unseres Codes könnten wir Folgendes tun:

$totalRows: 101;

@mixin chartValue($data) {
  $result: $totalRows - $data;
  grid-row-start: $result;
}

@for $i from 1 through $totalRows {
  .bar-#{$i} {
    @include chartValue($i);
  }
}

Dies iteriert über alle Zeilen unseres Diagramms und generiert eine individuelle Klasse für diese Zeilengröße. Und so könnten wir unser Markup wie folgt aktualisieren:

<div class="bar-45"></div>
<div class="bar-100"></div>
<div class="bar-63"></div>
<div class="bar-11"></div>

Und da haben wir es! Wir müssen nicht für jedes unserer Elemente einzelne Klassen von Hand schreiben und können unser Diagramm einfach durch Ändern des Markups aktualisieren. Diese Sass-Schleife gibt viele ungenutzte Klassen aus, aber es gibt genügend Tools, um diese zu entfernen.

Eine letzte Sache, die wir mit unserem Grid tun können, ist, jede Spalte mit einer Farbe nach ungerade/gerade zu gestalten

[class*="bar"]:nth-child(odd) {
  background-color: #ff4136; 
}

[class*="bar"]:nth-child(even) {
  background-color: #0074d9;
}

Und da haben wir es! Ein responsives Diagramm, das mit CSS Grid erstellt wurde. Es gibt viel, was wir tun könnten, um diesen Code aufzuräumen. Das Erste, was wir wahrscheinlich tun sollten, ist sicherzustellen, dass wir semantisches Markup verwenden und ein Tool verwenden, um all diese Klassen zu entfernen, die von unserer Sass-Schleife ausgespuckt werden. Wir könnten uns auch damit beschäftigen, wie dieses Diagramm auf Mobilgeräten gerendert wird, und darüber nachdenken, wie wir jede Spalte und Achse des Diagramms beschriften sollten.

Aber vorerst ist dies nur der Anfang. Die TL;DR dieses Beitrags: CSS Grid kann für alle möglichen Dinge verwendet werden, nicht nur zum nebeneinander Setzen von Text und Bildern. Es eröffnet uns einen ganz neuen Zweig des Webdesigns zum Experimentieren.