Balkendiagramme mit CSS

Balkendiagramme mit CSSHinweis: 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

  1. Unser Zeichenblatt
  2. Achsen und Beschriftung
  3. Die Balken
  4. Darf’s ein wenig 3D sein?
  5. 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:

[cc lang=”css”]
#bardemo {
position:relative;
padding:0;
border: 1px solid #000;
font-family:verdana;
width:500px;
height:200px;
background: #fff;
}
[/cc]

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:

[cc lang=”html”]

[/cc]

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:

[cc lang=”css”]
#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;
}
[/cc]

Und natürlich der HTML-Teil:

[cc lang=”html”]

[/cc]

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:

[cc lang=”css”]
#bardemo div.title {
padding:0;
position:relative;
font:12px;
font-weight:bold;
top:5px;
text-align:center;
line-height:15px;
}
[/cc]

Und her mit dem Titel:

[cc lang=”html”]

Unser Beispieldiagramm

[/cc]

So einfach geht das:

Unser Beispieldiagramm

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:

[cc lang=”css”]
#bardemo div.unit {
padding:0;
position:absolute;
top:180px;
left:50px;
width:400px;
font-size:8px;
text-align:center;
}
[/cc]

Und wieder zusammenbauen:

[cc lang=”html”]

Unser Beispieldiagramm
%

[/cc]

Langsam kann man erahnen, worauf es hinausläuft:

Unser Beispieldiagramm
%

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).

[cc lang=”css”]
#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;
}
[/cc]

Die eigentlichen Beschriftungen kommen dann in unseren HTML-Code:

[cc lang=”html”]

Unser Beispieldiagramm
Wert A
Wert B
Wert C

%

[/cc]

Jetzt ist unsere Leinwand für die eigentlichen Balken bereit:

Unser Beispieldiagramm
Wert A
Wert B
Wert C

%

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:

[cc lang=”css”]
#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;
}
[/cc]

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:

[cc lang=”html”]

Unser Beispieldiagramm
37,5  
67,5  
100  

Wert A
Wert B
Wert C

%

[/cc]

Schon hätten wir bereits ein fertiges Diagramm:

Unser Beispieldiagramm
37,5  
67,5  
100  

Wert A
Wert B
Wert C

%

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:

[cc lang=”css”]
#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;
}
[/cc]

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:

Unser Beispieldiagramm
37,5  
67,5  
100  

Wert A
Wert B
Wert C

%

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:

[cc lang=”css”]
#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;
}
[/cc]

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:

[cc lang=”html”]

Unser Beispieldiagramm
37,5  
67,5  
100  

Wert A
Wert B
Wert C

%

[/cc]

Außerdem ergänzen wir den BODY-Tag unseres HTML-Dokuments so, dass nach dem Ladevorgang die JavaScript-Funktion show_bars() aufgerufen wird:

[cc lang=”html”]

[/cc]

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:

[cc lang=”html”]

[/cc]

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:
[cc lang=”javascript”]
/* 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;
[/cc]

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.

[cc lang=”javascript”]
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); } [/cc] 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!

7 thoughts on “Balkendiagramme mit CSS

  1. Optisch ist das wunderbar, aber der HTML-Code ist eine Div-Suppe, in der die Label und Werte in keinster Weise zusammenhängen.

    Suchmaschinen, Screen-Reader oder Browser ohne CSS können damit nix anfangen.

    Ich würde erstmal eine Strukturierte HTML-Grundlage zu erstellen (z.B. eine Definitionsliste oder eine Datentabelle) und diese dann mit CSS in ein Diagramm umzuformen.

    MfG
    Thomas

  2. Hallo Thomas,

    im Grunde hast Du natürlich vollkommen recht, jedoch ist dies kein Nachteil der hier vorgestellten Lösung gegenüber der Varianten aus Grafiken, JavaScript oder gar Flash. Eine vernünftige Tabelle gehört eigentlich bei einer Statistik immer dazu.

    Interessant ist aber der Ansatz, eine einfache Tabelle entsprechend mit CSS zu gestalten und so zwei Fliegen mit einer Klappe zu schlagen. Das werde ich mal für einen weiteren Artikel festhalten, um das hier vorgestellte Konzept um die Dimension “Barrierefreiheit” zu erweitern.

    Viele Grüße,
    André

  3. Naja, wenn man die Infos zusätzlich nochmal als Tabelle Darstellt had diese Version im Vergleich zu Bild, javaScript oder Flash trotzdem den Nachteil, das die Daten nochmal als Unstrukturierter Inhalt im HTML-Code stehen.

    Ich hab vor einiger Zeit auch mal einen CSS-Graph gebaut, der auf einer Tabelle basiert und über diverse CSS-Klassen gesteuert wird.

    Der Code unterstützt mehrere Charts in einem Diagramm, verschiedene “Themes” und einige weitere Optionen, die per CSS gesteuert werden können.
    Der Quellcode ist Kommentiert und kann gerne frei verwendet werden 🙂

    Der CSS-Code ist ziemlich komplex und in alten IEs funktioniert das nicht so ganz, aber als proof-of-concept ist es ganz brauchbar 😉

    Zu finden ist das Ganze unter https://dl.dropbox.com/u/1496903/tablegraph/index.html

    MfG
    Thomas

  4. Und wenn Du eh schon dabei bist, vielleicht könnte man sich die Umrechnerei sparen? Wenn man nur mit prozenualen Angaben arbeitet? Dummerweise könnte man dann keine absoluten Werte darstellen 😉

  5. @Thomas: Klar, im HTML steht es natürlich drin. Da müsste man es dann wiederum für Screenreader und Co. ausblenden. Deine Lösung sieht auf jeden Fall super aus, werde mir das nochmal im Detail ansehen 🙂

    @itst: Inwiefern magst Du denn das Umrechnen sparen? 1 Prozentpunkt auf 1 Pixel würde die Graphen doch recht mickrig machen 😉 Oder verstehe ich Dich da falsch? Mit einem passenden PHP-Skript dahinter (oder etwas JavaScript) fällt das Umrechnen dann aber eh weg. Wie gesagt… ich bin noch nicht fertig damit 🙂

Comments are closed.