Balkendiagramme mit CSS
06.07.2010 von André Bräkling
Hinweis: Eine optimierte (da einfacher, kompakter und barrierefrei) Variante mit TABLE findet sich in diesem Artikel.
Möchte man auf einer Webseite Statistiken angemessen aufbereiten, dann kommt man kaum an entsprechenden Grafiken vorbei. Bei einmaligen, statischen Werten können Diagramme natürlich mit einer beliebigen Software erstellt und als Grafiken eingebunden werden. Aber wie geht man mit dynamischen Werten um? Für nur wenige Graphen lohnt es sich meist nicht, eine umfangreiche Bibliothek zur dynamischen Erzeugung einzurichten und sich darin einzuarbeiten. Externe Lösungen, wie z.B die Google Chart API, bergen hingegen eine gewisse Abhängigkeit von einem Drittanbieter. In diesem Tutorial möchte ich deshalb erläutern, wie sich einfache Balkendiagramme problemlos mit CSS umsetzen lassen. Es geht dabei lediglich um die Gestaltung, in einem weiteren Beitrag werde ich dann die dynamische Erzeugung via PHP behandeln.
Die hier vorgestellte Methode ist eigentlich nichts besonderes, zeichnet sich aber insbesondere dadurch aus, dass sie sich vollkommen mit Bordmitteln umsetzen lässt. Wie bereits erwähnt, sind auf der Serverseite keine Bibliotheken zur Grapherstellung notwending. Aber auch der Client braucht weder JavaScript, noch Flash oder irgendein sonstiges Plugin. Natürlich steckt ein gewisser Aufwand dahinter, wenn man jedes Balkendiagramm einzeln zusammenbauen muss, jedoch soll diese Detailerklärung des Aufbaus ja eher für den “Einmaleinsatz” und zum allgemeinen Verständnis dienen. Doch jetzt genug der langen Vorrede – los geht’s:
Inhalt
- Unser Zeichenblatt
- Achsen und Beschriftung
- Die Balken
- Darf’s ein wenig 3D sein?
- Doch ein wenig JavaScript?
1. Unser Zeichenblatt
Zunächst definieren wir einen Bereich, innerhalb dessen wir unser Diagramm gestalten wollen. Wir beginnen mit dem Stylesheet:
1 2 3 4 5 6 7 8 9 | #bardemo { position:relative; padding:0; border: 1px solid #000; font-family:verdana; width:500px; height:200px; background: #fff; } |
Unser Zeichenblatt wird über eine eindeutige ID bardemo benannt. Wir setzen die Position auf relative, damit wir die einzelnen Unterelemente innerhalb unserer Leinwand positionieren können.
Dazu gehört natürlich auch das entsprechende DIV im Body unseres HTML-Dokumentes:
Schon haben wir unsere Leinwand:
2. Achsen und Beschriftung
Wie wir es in der Schule gelernt haben, versehen wir unser Zeichenblatt jetzt erstmal mit den Achsen, in die wir nachher unsere Balken einfügen wollen. Dazu positionieren wir ein weiteres DIV innerhalb des bardemo-DIV. Wieder erstmal die Style-Angaben:
1 2 3 4 5 6 7 8 9 10 | #bardemo div.axis { padding:0; position:absolute; top:30px; left:50px; width:400px; height:150px; border-bottom:1px solid black; border-left:1px solid black; } |
Und natürlich der HTML-Teil:
So sieht das dann aus (der Hintergrund ist nur für das Beispiel eingefärbt):
Nun spendieren wir unserem Diagramm noch einen Titel, damit auch jeder weiß, womit er es zu tun hat. Hierfür verwenden wir ein weiteres DIV mit passenden Style-Angaben:
1 2 3 4 5 6 7 8 9 | #bardemo div.title { padding:0; position:relative; font:12px; font-weight:bold; top:5px; text-align:center; line-height:15px; } |
Und her mit dem Titel:
1 2 3 4 5 |
So einfach geht das:
Außerdem müssen wir unsere Achsen beschriften. Da die Balken in diesem Beispiel horizontal ausgerichtet sein sollen, d.h. von links nach rechts, schreiben wir zunächst die Einheit an die x-Achse. Auch für dieses DIV brauchen wir wieder den passenden Style:
1 2 3 4 5 6 7 8 9 | #bardemo div.unit { padding:0; position:absolute; top:180px; left:50px; width:400px; font-size:8px; text-align:center; } |
Und wieder zusammenbauen:
1 2 3 4 5 6 |
Langsam kann man erahnen, worauf es hinausläuft:
Bisher haben wir eigentlich nur die festen Elemente auf unserer Leinwand verteilt. Nun wollen wir aber an der y-Achse die Beschriftungen für die einzelnen Balken anbringen. Wir entscheiden uns nun für drei Balken, wodurch wir die Positionen der Labels festlegen können. Jeder Balken soll 30 Pixel hoch werden, zusätzlich sollen sie 15px Abstand voneinander haben. Wir definieren nun die Styles für die Umgebung der Labels labels, allgemeine Angaben für alle Labels label und dann die Details für die einzelnen Labels label_x (Abstand von oben top und Farbe color).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #bardemo div.labels { padding:0; position:absolute; top:30px; left:10px; width:40px; height:150px; line-height:30px; } #bardemo div.label { position:absolute; left:0; height:30px; padding:0; font-size:8px; } #bardemo div.label_1 { top:15px; color:#c00; } #bardemo div.label_2 { top:60px; color:#0c0; } #bardemo div.label_3 { top:105px; color:#00c; } |
Die eigentlichen Beschriftungen kommen dann in unseren HTML-Code:
1 2 3 4 5 6 7 8 9 10 11 |
Jetzt ist unsere Leinwand für die eigentlichen Balken bereit:
3. Die Balken
Jetzt möchten wir natürlich auch die richtigen Balken einzeichnen. Die Positionen sind soweit klar, wir müssen uns nur noch ansehen, wieviele Pixel einem Prozent entsprechen. Unser Zeichenbereich für die Balken innerhalb der Achsen ist exakt 400 Pixel breit, d.h. 4 Pixel entsprechen 1%. Dadurch können wir unsere Graphen in 0,25%-Schritten darstellen, bei kleineren Unterschieden müssten wir runden. Für eine einfache Visualisierung sollte diese Genauigkeit aber ausreichen. Die Demobalken sollen die Werte 37,5% (=150px), 67,5% (=270px) und 100% (=400px) darstellen. Wieder schreiben wir die für alle Balken gültigen Werte in eine eigene Klasse bar, während die individuellen Angaben (Breite width, Farbe background und Abstand von oben top) in eigenen Klassen bar_x stehen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #bardemo div.bar { position:absolute; left:0; height:20px; padding:10px 0 0 0; text-align:right; font-size:10px; color:#fff; font-weight:bold; } #bardemo div.bar_1 { top:15px; width:150px; background:#c00; } #bardemo div.bar_2 { top:60px; width:270px; background:#0c0; } #bardemo div.bar_3 { top:105px; width:400px; background:#00c; } |
Außerdem soll die konkrete Wert rechtsbündig im Balken angezeigt werden. Damit diese Zahl nicht direkt am Rand klebt, fügen wir nach rechts noch ein Leerzeichen &bsp; ein:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <div id="bardemo"> <div class="title">Unser Beispieldiagramm</div> <div class="axis"> <div class="bar bar_1">37,5 </div> <div class="bar bar_2">67,5 </div> <div class="bar bar_3">100 </div> </div> <div class="labels"> <div class="label label_1">Wert A</div> <div class="label label_2">Wert B</div> <div class="label label_3">Wert C</div> </div> <div class="unit">%</div> </div> |
Schon hätten wir bereits ein fertiges Diagramm:
4. Darf’s ein wenig 3D sein?
Diagramme sind meistens nicht sonderlich spannend. Aber mit ein paar grafischen Finessen kann man es aber geschickt aufwerten. (Zumindest solange man es nicht übertreibt… auch hier gilt: Weniger ist manchmal mehr!) CSS3 bietet hierzu tolle Möglichkeiten, aber zur Zeit sollten wir uns der Kompatibilität wegen lieber mit dem zufrieden geben, was CSS2 uns ermöglicht. Beispielsweise können wir den Balken mit einer Hintergrundgrafik durch einen Farbverlauf einen leichten 3D-Effekt spendieren. Andere Möglichkeiten wären auch Grafiken mit Schatten oder eine zusätzliche Grafik, die den Balken mit runden Ecken abschließt. Hier wollen wir als Beispiel einfach eine Hintergrundgrafik aus einem CSS-Sprite einfügen. So sieht die Grafik aus, wobei sie hier etwas verbreitert angezeigt wird, da die eigentliche Datei (365 Bytes) nur 1px breit ist:
Um unsere Grafik zu nutzen, müssen wir lediglich die CSS-Klassen der Balken etwas anpassen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #bardemo div.bar_1 { top:15px; width:150px; background:#c00 url(bar_sprite.png); } #bardemo div.bar_2 { top:60px; width:270px; background:#0c0 url(bar_sprite.png); background-position:0 -30px; } #bardemo div.bar_3 { top:105px; width:400px; background:#00c url(bar_sprite.png); background-position:0 -60px; } |
Dadurch wird jedem DIV die Hintergrundgrafik bar_sprite.png hinzugefügt, die bei Balken 2 und 3 via background-position entsprechend verschoben wird. Mehr zur Verwendung von CSS-Sprites findet ihr im zugehörigen Artikel. Die Hintergrundfarbe steht hier im Beispiel immer noch in den Style-Klassen, wodurch die Darstellung auch gelingt, wenn die Grafik nicht geladen werden kann bzw. mit Verzögerung geladen wird.
So sieht es dann aus:
Damit ist unser Bordmittel-Balkendiagramm auch schon fertig. Im letzten Abschnitt möchte ich zusätzlich noch zeigen, wie man den Graphen via JavaScript noch etwas aufpeppen kann.
5. Doch ein wenig JavaScript?
Da sich CSS-Eigenschaften via JavaScript manipulieren lassen, kann man (sofern man eben nicht nur mit HTML und CSS auskommen muss bzw. möchte) dem Diagramm noch etwas zusätzlichen Pepp verleihen. Beispielsweise könnte man sie dynamisch manipulierbar machen. An dieser Stelle möchte ich zeigen, wie die Balken beim Seitenaufruf in einer kleinen Animation “herausfahren” können. Dazu ändern wir zunächst die CSS-Klassen so, dass die Balken zu Beginn nur 0px breit sind:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #bardemo div.bar_1 { top:15px; width:0px; background:#c00 url(bar_sprite.png); } #bardemo div.bar_2 { top:60px; width:0px; background:#0c0 url(bar_sprite.png); background-position:0 -30px; } #bardemo div.bar_3 { top:105px; width:0px; background:#00c url(bar_sprite.png); background-position:0 -60px; } |
Im HTML entfernen wir zusätzlich die Beschriftungen, die erst nach dem vollständigen Ausfahren der Balken erscheinen soll. Außerdem ergänzen wir für die Balken IDs, damit wir leichter darauf zugreifen können:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <div id="bardemo"> <div class="title">Unser Beispieldiagramm</div> <div class="axis"> <div id="bardemo_bar1" class="bar bar_1">37,5 </div> <div id="bardemo_bar2" class="bar bar_2">67,5 </div> <div id="bardemo_bar3" class="bar bar_3">100 </div> </div> <div class="labels"> <div class="label label_1">Wert A</div> <div class="label label_2">Wert B</div> <div class="label label_3">Wert C</div> </div> <div class="unit">%</div> </div> |
Außerdem ergänzen wir den BODY-Tag unseres HTML-Dokuments so, dass nach dem Ladevorgang die JavaScript-Funktion show_bars() aufgerufen wird:
1 | <body onload="javascript:show_bars();"> |
Vor dem schließenden BODY-Tag, also am Ende unseres Dokumentes, fügen wir nun noch eine Skript-Sektion ein, die den folgenden JavaScript-Code enthalten soll:
Also machen wir uns jetzt an das eigentliche Skript. Zunächst wollen wir ein paar notwendige Variablen definieren, die im Ablauf verwendet werden und uns eine leichte Anpassung der Parameter ermöglichen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* Balkenobjekte */ var bardemo_bars = new Array( document.getElementById('bardemo_bar1'), document.getElementById('bardemo_bar2'), document.getElementById('bardemo_bar3') ); /* Startwerte der Balken */ var bardemo_current = new Array(0,0,0); /* Zielwerte der Balken */ var bardemo_target = new Array(37.5, 67.5, 100); /* Schrittweite */ var bardemo_step = 0.25; /* Verzoegerung zwischen Schritten in ms */ var bardemo_time = 100; |
Jetzt brauchen wir auch die zu Beginn aufgerufene show_bars()-Funktion. Sie durchläuft die einzelnen Balken aus dem Array bardemo_bars in einer Schleife und überprüft, ob der aktuelle Wert des Balkens aus bardemo_current bereits der Ziellänge aus bardemo_target entspricht. Wurde die Länge noch nicht erreicht, dann wird der Wert um bardemo_step erhöht und die Länge des Balken auf den entsprechenden Pixel-Wert gesetzt. Sollte sie stattdessen erreicht sein, wird der Zielwert noch als Label im Balken ausgegeben.
Abschließend definiert die Funktion, sofern noch nicht alle Balken fertig sind, dass sie in bardemo_time Millisekunden wieder ausgeführt werden soll.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function show_bars() { /* Schalter: Sind wir fertig? */ var done = true; /* Balken durchlaufen */ for (var i = 0; i < bardemo_bars.length; i++) { if (bardemo_current[i] < bardemo_target[i]) { /* Max. Laenge nicht erreicht */ /* Balken ist noch nicht fertig */ done = false; /* Um Schrittweite erhoehen */ bardemo_current[i] += bardemo_step; /* DIV auf entsprechende Laenge setzen 1 Step = 1 Pixel */ bardemo_bars[i].style.width = (bardemo_current[i] / bardemo_step) + 'px'; } else { /* Max. Laenge erreicht */ /* Label in Balken schreiben */ bardemo_bars[i].innerHTML = bardemo_target[i] + ' '; } } /* Wenn nicht fertig, dann show_bars() in bardemo_time ms erneut ausfuehren */ if (!done) window.setTimeout("show_bars()",bardemo_time); } |
Minimiert man alles, dann hat man so ein animiertes Balkendiagramm mit weniger als 3 Kilobyte. Eine Demo findet ihr im Testlabor. Und jetzt viel Spaß damit!
Weitere Artikel zum Thema:

