Mit verschiedenen Maßeinheiten in CSS rechnen: Die calc() Funktion


Will man in seinem Stylesheet Berechnungen anstellen denkt man heutzutage sofort an SASS oder "zumindest" LESS. Schließlich kann man hier komplexe Formeln hinterlegen und mit Variablen arbeiten und so ein komplettes Layout mit wenigen Anpassungen neu "ausrechnen". Aber SASS und LESS sind eben Präprozessoren. Sie stellen die Berechnung an lange bevor das Stylesheet im Browser des Users geladen wird. Was 100% Breite in Pixeln bedeutet, oder 100px in Prozent weiß zu diesem Zeitpunkt niemand. Schließlich hängt das ja von dem individuellen Endgerät ab. Relative und absolute Werte können so also nicht zusammen berechnet werden.

So etwas wie:

.a{ height: (100% + 100px); }

kann z.B. in SASS nicht funktionieren.

Schließlich sind 100% + 100px auf einem Smartphone etwas komplett anderes als auf einem Desktop Rechner. Man müßte also JavaScript bemühen. Aber warum in die Ferne schweifen wenn das Gute so nah liegt?

Die calc() Funktion direkt in CSS

Mit der calc() Funktion lassen sich solche Berechnungen direkt in CSS ausführen und zwar genau zu dem Zeitpunkt zu dem das Stylesheet bei dem Client im Browser geladen wird. Das sieht dann so aus:

.a{ height: calc(100%+100px); }

und funktioniert schon seit langem erstaunlich gut in (fast) allen Browsern. Nur IE8 und und ältere Versionen können damit nichts anfangen. Siehe Can I use... Mit der calc() Funktion lassen sich auch wunderbar komplexere Berenungen durchführen. Zum Beispiel:

.a{ width:calc(50%/2 - 3*5px); }

Hintergrund und Anwednungsbeispiele

Eigentlich wurde die calc() Funktion eingeführt um ein Problem zu lösen, dass wenig später eleganter durch box-sizing:border-box; gelöst wurde: Die Kombination einer relativen Breite mit einem absoluten Rahmen. Zwei 50% breite Elemente zum Beispiel funktionieren gut nebeneinander. Gibt man diesen Elementen jetzt aber noch einen Rahmen mit 1px Breite mit ist alles zusammen 100% + 4px breit. Damit rutscht das zweite Element unter das erste. Mit:

.element1, .element2 { width:calc(50% - 2px); border:1px solid #eee; }

kann man dieses Problem lösen. Eleganter geht es aber eben mit:

.element1, .element2 { box-sizing:border-box; width:50%; border:1px solid #eee; }

box-sizing:border-box; wird eben sogar durch IE8 unterstützt und ein lästiges nachrechnen bei der Änderung der Breite des Rahmens entfällt. Das Element ist mit Rahmen eben 50% groß, egal ob der Rahmen nun eine Breite von 1px, 10px oder 100px hat. Mit der calc() Funktion müßte man den Abzug von "-2px" jedes Mal anpassen bzw. eine eigene Klasse für anlegen.

Gerade weil das akute Problem anderweitig gelöst wurde ist die calc() Funktion wohl etwas in Vergessenheit geraten. Dennoch gibt es auch heute noch sinnvolle Anwendungsbeispiel für deren Nutzung. Auf die schnelle hab ich folgendes schöne Beispiel gefunden:

indicius.comindicius

Das blaue, absolut positionierte Hintergrundelement ist 100% + 480px hoch. Damit liegt es immer hinter dem kompletten Header-Bereich UND hinter den ersten Content Elementen. Hier wäre auch der Umgekehrte Weg denkbar: Ein 100% hoher Header Bereich ABZÜGLICH der Höhe der ersten Contentelemente. So könnte man sicher gehen das der Header zwar den größt möglichen Platz erhält, die Content Elemente aber immer "above the fold" bleiben.

Als weiteres Beispiel wäre da noch eine Navigationsleiste mit fester Höhe die zusammen mit einem nicht absolut positionierten Header-Bereich zusammen immer 100% Höhe des Browserfensters haben soll. Und, und, und.

Bei längerem nachdenken dürfte jedem der ein oder andere sinvolle Anwendungsbereich einfallen.

Fazit

Alt, wenig bekannt aber dennoch auch heute noch sinnvoll. Gerade bei der horizontalen Größenberechnung in einem responsiven Layout durch aus nützlich.