Ein paar Anwendungsfälle für Calc()

Avatar of Chris Coyier
Chris Coyier am

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

calc() ist eine native CSS-Methode, um einfache Berechnungen direkt in CSS durchzuführen und jeden Längenwert (oder so ziemlich jeden Zahlenwert) zu ersetzen. Sie verfügt über vier einfache mathematische Operatoren: Addition (+), Subtraktion (-), Multiplikation (*) und Division (/). Die Möglichkeit, Berechnungen im Code durchzuführen, ist eine nette und willkommene Ergänzung zu einer Sprache, die ziemlich zahlengesteuert ist.

Aber ist sie nützlich? Ich habe mir in der Vergangenheit den Kopf zerbrochen, um offensichtlich nützliche Fälle zu finden. Es gibt aber definitiv einige.

Können Präprozessoren nicht unsere Berechnungen durchführen?

Alle CSS-Präprozessoren verfügen über mathematische Funktionen, und sie sind ziemlich nützlich. Aber sie sind nicht ganz so leistungsfähig wie native Berechnungen. Die nützlichste Fähigkeit von calc() ist ihre Fähigkeit, Einheiten zu mischen, wie z. B. Prozente und Pixel. Kein Präprozessor wird jemals dazu in der Lage sein. Dies ist etwas, das zur Renderzeit geschehen muss.

Syntax

.thing {
  width: 90%; /* fallback if needed */
  width: calc(100% - 3em);
}

Um den mathematischen Operator herum müssen Leerzeichen vorhanden sein. Man kann verschachteln.

Browser-Unterstützung

Es ist überraschend gut. Kann ich verwenden... ist immer großartig, um die Details dort zu überprüfen. Auf Desktops wären die Bedenken, dass es IE 9+, Safari 6+ ist und erst in Opera enthalten sein wird, wenn es auf Blink in 15+ ist. Auf Mobilgeräten unterstützen Android und Opera Mini es noch gar nicht, und iOS nur ab 6.0+.

Sie müssen die Entscheidung dort treffen. Ich konnte es bereits in bestimmten Szenarien in der Produktion tatsächlich einsetzen.

Anwendungsfall #1: (Volle Höhe – Header)

Ein blockbasiertes untergeordnetes Element mit height: 100% ist so hoch wie sein blockbasiertes Elternelement. Es kann in einigen Fällen schön sein, ein farbiges Modul so hoch wie das Elternelement zu machen.

Aber nehmen wir an, das Elternelement wird zu klein, um den gesamten Inhalt des Moduls zu enthalten. Sie möchten, dass der Inhalt scrollt, aber Sie möchten, dass *nur* der Inhalt scrollt, nicht das gesamte Modul. Setzen Sie einfach overflow-y: auto; richtig? Nicht ganz, denn overflow-y ist nur nützlich, wenn das Inhaltselement selbst eine festgelegte Höhe hat, die überlaufen kann. Wir können das Inhaltselement nicht 100% hoch machen, denn mit dem Header dort ist das zu hoch. Wir brauchen 100% *abzüglich* der Höhe des Headers. Wenn wir diese Header-Höhe kennen, ist es machbar!

* {
  /* So 100% means 100% */
  box-sizing: border-box;
}
html, body {
  /* Make the body to be as tall as browser window */
  height: 100%;
  background: #ccc;
  padding: 20px;
}
body {
  padding: 20px;
  background: white;  
}
.area-one {
  /* With the body as tall as the browser window
     this will be too */
  height: 100%;
}
.area-one h2 {
  height: 50px;
  line-height: 50px;
}
.content {
  /* Subtract the header size */
  height: calc(100% - 50px);
  overflow: auto;
}

Sie könnten sich beschweren, dass der Header keine feste Größe haben sollte. Es könnte irgendwann cool sein, wenn calc() gemessene Größen von Elementen subtrahieren könnte, aber das ist noch nicht möglich. Sie könnten den Header mit Ellipsen überlaufen lassen.

Check out this Pen!

Anwendungsfall #2: X Pixel von der unteren rechten Ecke

Wir können Hintergrundbilder X Pixel von der oberen linken Ecke einfach positionieren.

background-image: url(dog.png);
background-position: 50px 20px;

Das würde den Hund 50 Pixel von links und 20 Pixel von oben vom Kasten des Elements positionieren. Aber was, wenn Sie ihn 50 Pixel von rechts und 20 Pixel von unten haben möchten? Mit reinen Längenwerten nicht möglich. Aber calc() macht es möglich!

background-image: url(dog.png);
background-position: calc(100% - 50px) calc(100% - 20px);
Check out this Pen!

Anwendungsfall #3: Feste Spaltenabstände ohne Elternelemente

Nehmen wir an, Sie möchten zwei Spalten nebeneinander haben. Die erste 40% breit, die zweite 60%, aber mit einem festen Abstand von 1em zwischen den Spalten. Keine überkomplizierten Grids haben feste Spaltenabstände, aber sie sind keine echten Spaltenabstände im eigentlichen Sinne. Die Spalten stoßen direkt aneinander und die Spalten werden durch interne Polsterung innerhalb dieser Spalten erzeugt.

Mit calc() können wir die erste Spalte 40% breit machen mit einem rechten Rand von 1em, dann die zweite Spalte 60% breit abzüglich dieses 1em.

.area-one {
  width: 40%;
  float: left;
  margin-right: 1em;
}

.area-two {
  width: calc(60% - 1em);
  float: right;
}

Sie könnten die Hälfte des Spaltenabstands von beiden entfernen, wenn Sie die Proportionen genauer beibehalten möchten. Jetzt haben Sie zwei echte Spalten, die durch einen festen Abstand getrennt sind, ohne Elternelemente oder interne Polsterung verwenden zu müssen.

Check out this Pen!

Anwendungsfall #4: Zeigen, dass Mathematik leichter zu verstehen ist

Wo wir gerade bei Spalten sind, manchmal wird die Divisionsmathematik unübersichtlich. Nehmen wir an, Sie möchten ein 7-Spalten-Raster, Sie könnten Klassen haben wie

.column-1-7 {
   width: 14.2857%
}
.column-2-7 {
   width: 28.5714%
}
.column-3-7 {
   width: 42.8571%
}

Nicht gerade magische Zahlen, aber auf den ersten Blick schwer zu verstehen.

.column-1-7 {
   width: calc(100% / 7);
}
.column-2-7 {
   width: calc(100% / 7 * 2);
}
.column-3-7 {
   width: calc(100% / 7 * 3);
}
Check out this Pen!

Anwendungsfall #5: Eine Art schlechter Box-Sizing-Ersatz

Ich bin ein Fan von universellem box-sizing: border-box;, weil man dann nicht viel rechnen muss, um herauszufinden, wie groß ein Element tatsächlich ist, oder diese Berechnungen anzupassen, wenn sich Dinge wie Rahmen und Polsterung ändern.

Wenn Sie nachbilden möchten, was box-sizing tut, könnten Sie calc() verwenden, um die Werte nach Bedarf abzuziehen.

.module {
  padding: 10px;

  /* Same as box-sizing: padding-box */
  width: calc(40% - 20px);

  border: 2px solid black;

  /* Same as box-sizing: border-box */
  width: calc(40% - 20px - 4px);
}

box-sizing hat eine weitaus bessere Browserunterstützung als calc(), daher würde dies selten verwendet werden.

Die Zukunft?

Ich denke, es wird interessant sein, wenn wir die attr()-Funktion auch in anderen Bereichen als der content-Eigenschaft verwenden können. Damit könnten wir Werte aus HTML-Elementen extrahieren, Berechnungen daran durchführen und die neuen Zahlen für Designzwecke verwenden. Zum Beispiel das Einfärben von Eingabefeldern basierend auf den enthaltenen Zahlen.

Vielleicht könnten wir damit auch ausgefallene Dinge mit den <progress>-Elementen machen, wie sie in einen Tachometer zu verwandeln, wie auf dieser Seite. Vielleicht etwas wie

/* Not real */
progress::progress-bar {
  transform: rotate(calc(!parent(attr(value))*18)) + deg);
}