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);
}
Die eine Sache, die ich wirklich kontraintuitiv an calc finde, ist, dass 100% immer wie 100VH (oder 100VW) zu sein scheint, und doch wird dies in der Dokumentation über calc nicht generell bestätigt. Für mich
.foo {
width: calc(100%-3em);
}
ist 100% des direkten Elternelements, nicht des Fensters. Ich befürchte, dass calc weiterhin von begrenztem Wert sein wird, bis wir sagen können calc(#bar(width) -3em); und wissen, dass das funktioniert.
Ich glaube nicht, dass es dokumentiert ist, weil es nicht stimmt. Solange das Elternelement eine definierte Breite hat (und Ihr Element nicht fixiert ist), wird es immer relativ zu seinem Elternelement sein. Beispiel: http://codepen.io/ggilmore/pen/d8fc7309e1fc387f8965e66674ac031c
Danke.. sehen Sie, das macht Sinn und ich glaube, es ist das erste Mal, dass es für mich gut Sinn ergibt. Selbst als ich meinen ursprünglichen Beitrag schrieb, habe ich mich selbst in Frage gestellt. Es ist möglich, dass es sich um meine eigenen Vorurteile handelt, aber ich weiß immer noch nicht, ob ich auf einen Satz gestoßen bin, der so einfach ist wie Ihre Antwort. Obwohl, ist es "definierte Breite" oder "definierte relative Dimension" (d. h. Höhe: calc(100% – 30px) wie in Chris' ursprünglichem Beispiel scheint darauf hinzudeuten, dass dies die Höhe und nicht die Breite messen würde.
Ja, das meinte ich. Ich sagte nur Breite wegen des Beispiels.
Ein ausgezeichneter und informativer Beitrag… ich habe calc() Schülern beigebracht, hatte aber Schwierigkeiten mit guten Anwendungsfällen… die von Ihnen oben beschriebenen sind großartige Ideen… danke fürs Teilen…
Ich wünschte mir nur, die mobile Unterstützung wäre besser… aber das wird sich mit der Zeit verbessern…
Wusste nicht einmal von calc(), wünschte, ich hätte das schon vor Jahren gewusst! Es hätte so viel Zeit gespart! Danke, dass Sie darüber geschrieben haben!
Das ist gut, Chris. Ich denke, die Verwendung von calc gibt Ihnen nicht die exakte Größe der Seiten, die Sie benötigen, da sie zu groß sein wird. Gibt es eine Möglichkeit, die drei Seiten gleich zu machen.
Danke.
Tab Atkins hat über Lea Verous Beitrag zu calc() und attr() angedeutet, dass die CSSWG zugestimmt hat, dass attr() in calc() erlaubt sein sollte, also ist es nur eine Frage der Zeit, bis es implementiert wird?
Es wäre ziemlich nett, einfache Balkendiagramme basierend auf Attributwerten erstellen zu können, ohne auf js zurückgreifen zu müssen.
Weiß jemand, ob die Verwendung von calc() Leistungseinbußen hat? Eine schnelle Google-Suche ergab wenig Informationen.
Das ist wirklich hilfreich.
Danke fürs Teilen
Nun, diese Fälle sind mit älteren Techniken machbar.
Insbesondere für #2 können Sie Schlüsselwörter verwenden, die angeben, von welcher Kante der Offset gegeben wird, dank CSS Backgrounds and Borders Module Level 3
Interessanterweise unterstützt Safari 6.0 die von Ihnen erwähnte Syntax für den Hintergrund-Offset nicht, sodass Sie calc verwenden können, um eine noch bessere Unterstützung zu erzielen. Genial!
http://caniuse.com/background-img-opts
Ja, diese Art der Positionierung wurde erst kürzlich in Webkit implementiert: Ende 2012. Schade für Webkit. Siehe Bug 37514.
Hallo, im Anwendungsfall #3 müssen Sie aufgrund des Box-Modells auch die Polsterung des zweiten Bereichs abziehen; es würde so aussehen
width: calc(60% – 1em – 4 * 30px);
ciao
Toller Artikel wie üblich, Chris, eine Frage jedoch.
Bezüglich der Abwärtskompatibilität, würden Sie Ihr Grid-Ersatzbeispiel so angehen?
.column-2-7 {width: 28.5714%;
width: calc(100% / 7*2);
}
Ich weiß, manche würden sagen, es ist Zeitverschwendung (und Bytes), aber es könnte eine großartige Möglichkeit sein, die (fast) magische Zahl zu verdeutlichen. Sinnlos vielleicht?
Sie könnten es auch einfach kommentieren
.column-2-7 {
width: 28.5714%; /* (100% / 7*2) */
}
Oh wow, ich habe Anwendungsfall #2 definitiv schon einmal gebraucht, jedes Mal, wenn diese Situation aufkam, habe ich calc komplett ignoriert..
Wenn ich also ein Hintergrundbild zentriert, aber versetzt haben möchte, kann ich dann z. B. "calc(centered – 50px)" haben? Oder streng Einheitenwerte (50% / 50px).
Ich werde später etwas spielen müssen, denke ich.
Ein wenig Hilfe benötigt. Kann ein Sticky-Footer mit calc erstellt werden?
Theoretisch ja, soweit ich weiß, vorausgesetzt, das Elternelement des Footers ist gleich hoch wie die Seite, ansonsten wird Ihre Formel kompliziert.
Aber könnten Sie nicht einfach
position: absolute; bottom: 0px;in Bezug auf den Footer-Div verwenden, um dasselbe Ziel zu erreichen?
Meine größte Enttäuschung, nachdem ich diesen Artikel gelesen habe, ist die mangelnde Unterstützung auf Android und anderen mobilen Browserplattformen für 'calc'.
Ich wollte calc verwenden, um einen Toggle-Style-Div, der ein Login-Formular enthält, relativ zu positionieren, damit er responsiv ist und auf der y-Achse zentriert erscheint.
Alles, was ich dann noch tun müsste, wäre, seine maximale Breite in Prozent für jeden Breakpoint zu steuern, zusammen mit Schrift-, Zeilenhöhen-, Polsterungs- und Randeigenschaften über @media-Abfragen. Ich denke, ich werde auch die Positionierung auf der y-Achse auf die gleiche Weise angehen müssen – zumindest für den Moment.
Es ist wie eine JavaScript-Funktion, mathematische Berechnung.
Anwendungsfall #2 kann erreicht werden, ohne
calc()zu verwenden. Um das zu erreichen, was im Demo gemacht wird, könnten Sie einfachDemo: http://codepen.io/skimberk1/pen/jdbli
Hii,
Chris, Sie sind ein Genie, Sie lösen Probleme wie das Bestreichen eines Brotes. Ich versuche, Ihnen im Bereich Design nachzueifern. Und ich mache es gut. Danke.
Anwendungsfall #2 ist großartig.
Ich möchte diese Funktion mehr nutzen, aber ich fürchte die Kosten für die Leistung… Hat jemand Zahlen dazu?
Das Maß an Unterstützung ist höher, als ich ursprünglich vermutet hätte… Kann jemand eine Phase sehen, in der Unterstützung und eine minimale Browserversion global übernommen werden, so dass es eine Basisunterstützung gibt, die Entwickler unterstützen und darauf aufbauen würden?
Nun, es ist nützlich, aber nicht übermäßig. Es wäre schön, calc mit Variablen auf diese Weise zu mischen
div { position:absolute;top:calc(50%- height / 2) }oder
li { width: calc ( 100% / counter ) }Wie schwierig wäre es, einen Polyfill für nicht unterstützte Browser zu schreiben? Wäre es das überhaupt wert?
Wenn ich mich richtig erinnere, scheint 100% in calc() die Breite des letzten position:relative Elternelements widerzuspiegeln.
Zumindest erinnere ich mich im Moment daran, also nehmen Sie es nicht als Gesetz, sondern als etwas, das man vielleicht bedenken sollte. Da praktisch alles von Server-Boot-Parametern über CSS bis hin zur gesamten dazwischenliegenden Programmierung auf meinem Schreibtisch landet, ist es manchmal schwer, sich präzise daran zu erinnern. :)
Die calc()-Funktion war hier ein sofortiger Erfolg, obwohl ich zugeben muss, dass es ein paar Kleinigkeiten gab, die ich mir gewünscht hätte, wie z. B. eine bedingte Syntax.
Was den attr()-Wert und die breite Verwendung jenseits der content-Eigenschaft betrifft, so läuft man in diesen Fällen Gefahr, auf die Eigenheiten der Instanz zu stoßen. Wenn sie hier (regelmäßig) verwendet wird, ist oft eine zusätzliche CSS-Regel erforderlich, die den Selektor der Regel, die attr() enthält, mit dem Selektor einer Regel zusammenführt, die jedes Element auf der Seite eindeutig identifiziert, auf das der Effekt angewendet werden soll.
Der Grund dafür ist einfach, dass jede Instanz wahrscheinlich einen eindeutigen Ergebniswert hat, jeder eine eindeutige Stelle in den CSS-Regeln benötigt, um den Wert zu speichern, im Gegensatz zu dem oft gesuchten gemeinsamen Wert von Klassen.
Leute stoßen regelmäßig auf dieses Instanzierungsverhalten, wenn sie versuchen, Animations-Keyframes in Echtzeit zu ändern und ähnliche Aktivitäten, aber die Lösung ist immer ziemlich einfach, sobald man bedenkt, dass, wenn sich ein Wert ändert, er seinen eigenen Regelslot benötigt, auf die eine oder andere Weise.
Oft haben die Leute das Gefühl, dass sie eine Regel erneut anwenden müssen, damit sie sich verbindet, aber eigentlich ist es nur die Tatsache, dass sie diesen separaten Regelslot haben, der den größten Unterschied macht.
Es ist eine wirklich großartige Möglichkeit, die Höhe eines Elements mit der "outline"-Eigenschaft zu gestalten. Andernfalls rutscht der Umriss in benachbarte Elemente, es sei denn, Sie geben einen Rand an. Vielen Dank fürs Posten! Es ist wirklich großartig!
Kudos für Fall #2. Das ist das Beste, was wir dafür verwenden könnten!
Calc()kann auch die Notwendigkeit von "inneren Wrapper"-Elementen eliminieren (wie z. B. ein 100% breiter Hintergrund mit einem festen Breiteninhalt), indempadding: 0 calc(50% - sitewidth / 2)auf das Elternelement angewendet wird. Beispiel hier.Dies funktioniert offensichtlich nicht mit
box-sizing: border-box, aber Sie könnten dieses spezielle Element wie im Beispiel gezeigt wieder aufcontent-boxzurücksetzen.Ich meine, wenn möglich, wer würde das nicht bevorzugen
Über das hier
Nein. 2 ist ein riesiger Gewinn.
Mein erster Gedanke war, dass dies eine gute Alternative zu border-box wäre, aber wie Sie sagen, überschreibt die Browserkompatibilität diese Möglichkeit.
Ich wollte dies für die vertikale Zentrierung verwenden. Ich habe ein Bild in einen Wrapper mit fester Höhe/Breite gelegt und versucht, so etwas zu tun
Sowohl FF als auch Chrome interpretieren dies als
-25%. Und sie tun dies basierend auf der Breite des Elternelements, anstatt der Höhe. Daher scheint es für diese Anwendung nicht zu funktionieren.Hat jemand eine bessere Lösung mit calc()? Es scheint, als wäre es eine großartige Alternative zur Verwendung eines zusätzlichen Wrappers und negativer Ränder.
Keines Ihrer Beispiele scheint in Firefox richtig zu funktionieren, da es die nicht vorangestellte Version der "box-sizing"-Eigenschaft *immer noch* nicht unterstützt. Das Hinzufügen von "-mox-box-sizing: border-box" zu Ihrer "*" Regel behebt das Problem.
Ich habe calc() verwendet, um ein responsives Grid mit festen Breiten für die Spaltenabstände einzurichten. Wenn Sie " $siteWidth: 960px;" in die gewünschte Breite ändern, ändern sich die Spalten in der Breite, aber die Spaltenabstände bleiben gleich. Worauf ich mich wirklich freue, ist die Verwendung von calc() mit CSS-Variablen. Stellen Sie sich vor, Sie ändern ein Grid, ohne es jedes Mal mit einer Media Query neu deklarieren zu müssen. Ändern Sie einfach die Variable und das gesamte Grid ändert sich. Ziemlich genial.
Hier ist ein reales Beispiel. Ich habe eine One-Page-Site für einen lokalen Honigstand erstellt und nutze sie, um mit neueren CSS-Funktionen zu experimentieren
http://beeladieshoney.com/
Das Hauptinhalts-
DIVverwendet mehrere CSS3-Hintergründe (Wabenmuster, Gras [unten] und Bienen [auch unten]). Um die Bienen zu positionieren, verwende ich diecalc-Eigenschaft, um bis ganz nach unten zu berechnen und dann 25 Pixel zurückzugehen. Ein Prozentwert funktioniert nicht sehr gut, da dieser mit zunehmendem Inhalt und aufgrund anderer Faktoren variiert, und ein fester Pixelwert würde aus denselben Gründen auch nicht funktionieren. Ich mache noch einige Cross-Browser-Tests, aber ich denke, ich habe die richtigen Fallbacks implementiert.Nebenbei bemerkt, die Animation, die ich angewendet habe, funktioniert nur in Firefox. Nun, sie funktionierte auch in Chrome mit dem
-webkit-Präfix, brach aber in Safari ab, also musste ich alle-webkit-Präfixe entfernen, wodurch sie leider auch in Chrome deaktiviert wurde. Sie sollte in jedem Browser funktionieren, der ein Update erhält und die von mir verwendeten Präfixe nicht mehr benötigt.