Berechnungen in CSS durchführen – calc()

Wenn man bisher gewohnt war, dass man mit CSS nicht rechnen konnte, kennt die CSS-Anweisung calc() nicht. Jetzt kann man sich natürlich fragen, für was das Gut sein kann. Eigentlich wollen wir dem Browser ja so wenig Arbeit wie möglich machen, damit dieser so schnell wie möglich unsere Website anzeigt und nicht fröhlich vor sich hinrechnet. Aber eins nach dem anderen.

calc() beim Einsatz von CSS-Höhe height
calc() beim Einsatz von CSS-Höhe height

Aufbau der CSS-Anweisung calc()

Anstelle eines Wertes für beispielsweise die Breite geben wir eine Berechnung an über calc(FORMEL).

In der Formel können wir mit +, - , * und / rechnen.

#bereich {
	width: calc(200px - 50px);
}

Das ist natürlich nicht wirklich einleuchtend, warum wir den Browser mit einer Grundschulaufgabe bei jedem Aufruf der CSS-Datei beschäftigen sollen (200-50 ergibt 150 – dass könnte man also auch gleich schreiben). Aber langsam mit den Pferden.

Das Besondere an calc ist: wir können mit verschiedenen Einheiten rechnen – sprich unser obiges Beispiel macht erst richtig Sinn, wenn hier relative Einheiten wie Prozent oder „em“ zum Einsatz kommen!

#bereich {
	width: calc(100% - 50px);
}

oder wilder:

#bereich {
	width: calc(100% - 2 * 50px + 1em);
}

Die CSS-Anweisung (mit seinen Präfixen) kann problemlos verwendet werden. Diese ist bei den meisten Browserversionen enthalten:

  • Firefox ab Version 16 (ab 4.0 mit –moz-calc)
  • IE ab Version 9
  • Chrome ab Version 26 (ab 19 mit –webkit-)
  • Safari ab Version 7 (ab 6 mit –webkit-)
  • Opera ab Version 15

Bitte an die alten Browserversionen also denken – im Produktiveinsatz sollten wir immer alle Browserpräfixe angeben (im folgenden Tutorial aus Gründen der Übersicht und des Platzes nicht). Hier jetzt einmal komplett.

Unsere kompletten Angaben sehen also immer wie folgt aus:

#bereich {
    width: -webkit-calc(100% - 2 * 50px + 1em);
    width: -moz-calc(100% - 2 * 50px + 1em);
    width: calc(100% - 2 * 50px + 1em);
}

Und als erste Anweisung können wir noch ein Fallback mitgeben, falls der Browser calc doch nicht verstehen sollte – also:

#bereich {
    width: 90%;
    width: -webkit-calc(100% - 2 * 50px + 1em);
    width: -moz-calc(100% - 2 * 50px + 1em);
    width: calc(100% - 2 * 50px + 1em);
}

Beispiel für Einsatz von calc()

Wir wollen als Beispiel 2 Bereiche nebeneinander platzieren, die zusammen die komplette Breite einnehmen. Beide Bereiche haben einen Rahmen von 5 Pixel (sieht nicht schön aus, aber ist sofort sichtbar).

Nachdem beide Bereiche zusammen die komplette Breite einnehmen sollen, bekommt jeder der Bereiche also 50%:

#bereich1, #bereich2 {
  float:left;
  border:5px solid orange;
  background-color: silver;
  width: 100%;
}

Und wo ist nun der Einsatz von unserer neuen CSS-Anweisung calc()? Bisher noch nicht – aber, wenn wir nun unser Beispiel ausführen, werden wir feststellen, dass beide Bereiche nicht nebeneinander sind, sondern untereinander. (Verd***t)

Woher kommt dieser Effekt? Die Erklärung ist ganz einfach (und wenn man das Problem noch nicht hatte, bereitet es nächtelang Kopfzerbrechen). Das klassische Box-Modell berechnet die verwendete Breite über Inhalt (das sind unsere 50%) plus den Rahmen (also 2 mal 5 Pixel) und den Außenbereich (den wir in diesem Beispiel unter Umständen auch noch haben, falls wir die Außenabstände nicht auf 0 gesetzt haben).

Probieren wir das Platzieren der 2 Bereiche auf die alte Art (diesmal ohne Rahmen):

*{
    margin: 0;
    padding: 0;
}

#bereich1, #bereich2 {
  float:left;
  /* border:5px solid orange; */
  background-color: silver;
  width:50%;
}

Jetzt sollten die 2 Bereiche nebeneinander angezeigt werden.

Wir wollen aber partout den Rahmen auch haben – und jetzt kommt unsere Berechnung zum Zuge. Wir müssen also jedem Bereich als Breite 50% minus der 2 mal 5 Pixel zuweisen:

Das Ganze sieht als Quellcode nun so aus:

#bereich1, #bereich2 {
  float:left;
  border:5px solid orange;
  background-color: silver;
  width:calc(100%/2 - 2*5px);
}

Funktioniert – super (die Präfixe für alte Browserversionen nicht vergessen, falls man das so einsetzen möchte.

Natürlich könnte man nun argumentieren, dass das Problem nur bei dem klassischen Box-Modell auftritt, und man sich viel Stress erspart, wenn man das neue Box-Modell nutzt (dazu einfach sich https://www.html-seminar.de/box-modell-box-sizing-border-box.htm ansehen). Diese Argumentation ist durchaus richtig. Der Vollständigkeit halber auch das Beispiel von oben mit dem neuen Box-Modell box-sizing:border-box;:

#bereich1, #bereich2 {
  float:left;
  border:5px solid orange;
  background-color: silver;
  width:50%;
   box-sizing:border-box;
}

Es gibt aber Fälle, in denen die CSS-Anweisung calc() extrem hilfreich ist und es auch keine andere bzw. althergebrachte Lösungsmöglichkeit gibt.

calc() in Hochform

Ich liebe Wortspielereien – aber hier passt diese zu 100%. Schauen wir uns das Problem an: man hat in CSS wenig Freude bei Höhen.

Wir erstellen uns eine Infobox, die eine Höhe von 100% einnimmt (und noch ein bisschen Außenabstand) und einen Scrollbalken anbietet, wenn zu wenig Höhe vorhanden ist. Hier sieht man gleich schön den praktischen Einsatz von der CSS-Anweisung calc()

calc() beim Einsatz von CSS-Höhe height
calc() beim Einsatz von CSS-Höhe height

Wollen wir einen Bereich angeben, der 100% an Höhe von unserem Bildschirm einnimmt lautet die CSS-Anweisung:

#infobox {
    height: 100%;
}

In dieser Infobox soll es einen Kopfbereich mit der Höhe von 40 Pixel geben – die vergebene ID im Beispiel ist „infoboxkopf“.

Der Rest von der Infobox kommt in unseren Bereich mit der ID „infoboxinhalt“.

<div id="infobox">
  <div id="infoboxkopf">
    <p>Infobox-Fenstertitel</p>
  </div>
  <div id="infoboxinhalt">
  	<p>Und hier kommt nun viel Inhalt, damit wir auch früher oder später mehr Inhalt haben, wie Platz auf dem Bildschirm vorhanden ist. Notfalls einfach nochmals den Text wiederholen und die Box sehr schmal machen.</p>
  	<p>Und hier kommt nun viel Inhalt, damit wir auch früher oder später mehr Inhalt haben, wie Platz auf dem Bildschirm vorhanden ist. Notfalls einfach nochmals den Text wiederholen und die Box sehr schmal machen.</p>
  </div>
</div>

Und nun zu unserem CSS-Code.

Um keine Überraschungen zu erleben, setzen wir alle Innen- und Außenabstände auf 0 und rechnen mit dem neueren und einfacheren Box-Modell:

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

Jetzt geben wir unserer HTML-Seite eine Höhe von 100% mit und eine Hintergrundfarbe, damit wir auch sehen, wo wir arbeiten. Zusätzlich definieren wir einen Innenabstand von 20 Pixeln:

html, body {
  height: 100%;
  background: #bbb;
  padding: 20px;
}

Unsere Infobox soll nun die Höhe von 100% und eine Breite von 200 Pixeln bekommen

#infobox {
  height: 100%;
  width: 200px;
}

In der Infobox der Bereich für die Kopfzeile bekommt eine Höhe von 40 Pixel und eine Hintergrundfarbe:

#infoboxkopf p {
  height: 40px;
  line-height: 40px;	
  background-color: orange;
  padding-left: 1em;
}

Unser Inhalt selber bekommt den Rest der Höhe – sprich hier kommt nun die Berechnung über calc() zum Einsatz:

#infoboxinhalt {
  height: calc(100% - 40px);
  overflow: auto;
  background-color: white;
  line-height: 1.6em;
  padding: 1em;
}

Die CSS-Anweisung overflow: auto; bewirkt, dass der Text, der nicht mehr vom Platz angezeigt werden kann (wir haben ja nur 100% vom Browserfenster) dann über einen Scrollbalken angesehen werden kann. Falls der Text komplett sichtbar ist, einfach das Fenster kleiner schieben.

Hier der komplette CSS-Code:

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html, body {
  height: 100%;
  background: #bbb;
  padding: 20px;
}
#infobox {
  height: 100%;
  width: 200px;
}
#infoboxkopf p {
  height: 40px;
  line-height: 40px;	
  background-color: orange;
  padding-left: 1em;
}
#infoboxinhalt {
  height: calc(100% - 40px);
  overflow: auto;
  background-color: white;
  line-height: 1.6em;
  padding: 1em;
}

Der Code zum ausprobieren gibt es unter:
https://www.html-seminar.de/beispielcode/calc.htm

Hier sieht man, dass die CSS-Anweisung calc() gute Dienste leisten kann. Hier gibt es keine andere (mir bekannte Lösung) für dieses Beispiel mit der Höhe (ohne dass man sich tierisch verbiegen müsste).