CSS/Funktionen/Math-Funktionen

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Die CSS Values and Units Module Spezifikation definiert für ihren Level 4 etliche CSS Funktionen, die bisher nur im Math-Objekt von JavaScript verfügbar sind. Damit sollen Berechnungen, die z. B. für Animationen benötigt werden, ohne den Einsatz von JavaScript oder gar Frameworks möglich werden.

Ana Tudor zeigt ein Anwendungsbeispiel in diesem CodePen.

Alle Funktionen akzeptieren, soweit nicht anders angegeben, Berechnungen als Argumente und können ihrerseits als Teil einer Berechnung verwendet werden. Eine Berechnung ist das, was Sie aus dem Inneren der calc() Funktion kennen. Die übergebenen Berechnungen müssen mit einem CSS-Typ durchgeführt werden, der für die verwendete Funktion sinnvoll ist. Hinweise dazu sind bei den einzelnen Funktionen angegeben.

CSS-Typen sind: einheitenlose Zahlen, Längen (z. B. px, em), Prozentangaben, Winkel (deg), Zeiten (s), Frequenzen (Hz), Auflösungen (dpi) oder Flexwerte (fr).

Beachten Sie: Diese Funktionen sind noch experimentell und die Browserunterstützung ist noch nicht sehr ausgeprägt. Eine produktive Nutzung setzt voraus, dass die großen Browser Chrome, Safari und Firefox sie unterstützen. Bitte beachten Sie die Links zu caniuse.com.
Beachten Sie: Die Kompatibilitätsinformationen zu Firefox, die Caniuse.com anzeigt und von Mozilla bezogen werden, sind inkorrekt. Die CSS Mathematikfunktionen sind nur in den nightly builds von Firefox verfügbar[1] (Stand Mai 2023).

Konstanten

Die folgenden Konstanten sind innerhalb von Berechnungsausdrücken zulässig und stehen für die angegebenen Werte. Außerhalb einer Berechnung werden sie wie normale Namen verwendet. Beispielsweise können Sie eine @keyframes Liste namens infinity problemlos erzeugen.

Die Konstanten e und pi sind für mathematische Zwecke zuweilen nützlich, bei infinity, -infinity und NaN sagt selbst die Spezifikation, dass ihr praktischer Nutzwert gering ist. Aber es sind gültige Werte für Zahlen im IEEE 754-Format und können deshalb bei Berechnungen entstehen, und wenn ein solcher Wert dann als Text dargestellt werden soll, werden diese Symbole benötigt.

e 2.71828... Eulersche Zahl, Basis des natürlichen Logarithmus
pi 3.14159... Verhältnis von Umfang zu Durchmesser eines Kreises
infinity Steht für den "positiv unendlich" Wert von IEEE 754
-infinity -∞ Steht für den "negativ unendlich" Wert von IEEE 754
NaN Steht für den "keine gültige Zahl" Wert von IEEE 754

Diese Groß- oder Kleinschreibung dieser Konstanten ist, wie bei allen CSS Schlüsselwörter, unerheblich.

Basisfunktionen

abs()

Syntax: abs(ausdruck)

Die abs()-Funktion berechnet den angegebenen Ausdruck (die Angabe von calc() ist nicht erforderlich!) und liefert den Absolutbetrag des Ergebnisses. [2]

sign()

Syntax: sign(ausdruck)

Die sign()-Funktion berechnet den angegebenen Ausdruck (die Angabe von calc() ist nicht erforderlich!) und gibt je nach Vorzeichen des Ergebnisses einen der folgenden Werte zurück[3]:

mod() und rem()

Syntax: mod(dividend-ausdruck, divisor-ausdruck)
rem(dividend-ausdruck, divisor-ausdruck)

Beide Funktionen berechnen die angegebenen Ausdrücke, teilen den Dividenden durch den Divisor und bestimmen dann den Rest der Division. Dividend und Divisor müssen dafür den gleichen Typ haben (Pixel durch Sekunden zu teilen ist nicht kompatibel).

mod() und rem() unterscheiden sich in zwei Punkten:

  • Vorzeichen des Rests: mod() übernimmt das Vorzeichen des Dividenden, rem() das Vorzeichen des Divisors
  • Rundung des Quotienten: mod() führt die Division durch und rundet den Quotienten ab. D.h. mod(-18,5) bildet den Quotienten -3.6 und rundet ihn zu -4 ab. rem() rundet dagegen zur Null hin, würde also -3 ermitteln. Zur Restbestimmung wird dann der Quotient mit dem Divisor multipliziert und vom Dividenden abgezogen. Für rem(−18,5) bedeutet das −18 − 5⋅(−3) = −3, was dem Verhalten des Modulo-Operators in JavaScript entspricht. Aber für mod(−18,5) ergibt sich −18 − 5⋅(−4) = 2, was unerwartet sein kann.

round()

Syntax: round(Ausdruck A, Ausdruck B)
round(Strategie, Ausdruck A, Ausdruck B)

Die round()-Funktion stellt eine allgemeine Möglichkeit zum Runden dar. Sie berechnet dazu die Ausdrücke A und B und wählt dann ein Vielfaches des Wertes von B aus, das dem Wert von A am nächsten kommt. Was dabei „am nächsten“ bedeutet, hängt von der festlegten Rundungsstrategie ab. Die Ausdrücke A und B müssen vom gleichen Typ sein[4].

nearest Default-Strategie - sucht dasjenige Vielfache von B, für das der Absolutbetrag der Differenz zu A am geringsten ist. Dies entspricht der kaufmännischen 4/5 Rundung oder dem Verhalten von Math.round().
up Sucht das kleinste Vielfache von B, das größer als oder gleich A ist. Dies entspricht dem Verhalten von Math.ceil().
down Sucht das größte Vielfache von B, das kleiner als oder gleich A ist. Dies entspricht dem Verhalten von Math.floor().
to-zero Sucht das Vielfache von B, zwischen 0 und A liegt und A am nächsten kommt. Dies entspricht dem Verhalten von Math.trunc().

round() stellt eine interessante Möglichkeit dar, einen Längenwert, der in einer beliebigen Längeneinheit angegeben sein kann (rem, vh, Prozent) auf ein Vielfaches eines Pixelrasters zu runden.

CSS round() auf 5px Raster
img {
   width: round(nearest, 20em, 5px);
}

Eine Rundung eines CSS number-Wertes auf eine Nachkommastellen könnte man mit round(wert, 0.1) erreichen.

Potenzen und Wurzeln

pow()

Syntax: pow(basis, exponent)

Die pow() Funktion berechnet beliebige Potenzen. Sowohl Basis wie auch Exponent müssen Ausdrücke sein, die einheitenlose Zahlen ergeben[5].

Die Exponentialfunktion kann dazu genutzt werden, um eine Wertefolge zu erzeugen, bei der das Verhältnis zwischen benachbarten Werten konstant ist (eine so genannte geometrische Folge). Wenn die Differenz d zwischen zwei Exponenten gleich ist, haben die Ergebnisse der Exponentialfunktion das gleiche Verhältnis ed.

Geometrische Folge im CSS
h1 { font-size: calc(1em * exp(1.5)); }
h2 { font-size: calc(1em * exp(1.25)); }
h3 { font-size: calc(1em * exp(1.0)); }
h4 { font-size: calc(1em * exp(0.75)); }

Die Potenzfunktion kann dazu genutzt werden, um eine Wertefolge zu erzeugen, bei der das Verhältnis zwischen benachbarten Werten konstant ist (eine so genannte geometrische Folge). Wenn die Differenz d zwischen zwei Exponenten gleich ist, haben die Ergebnisse der Potenzen das gleiche Verhältnis ad.

Geometrische Folge im CSS
h1 { font-size: calc(1em * pow(2, 1.50)); }
h2 { font-size: calc(1em * pow(2, 1.25)); }
h3 { font-size: calc(1em * pow(2, 1.00)); }
h4 { font-size: calc(1em * pow(2, 0.75)); }

exp()

Syntax: exp(ausdruck)

Die exp()-Funktion stellt den Sonderfall der pow()-Funktion mit der Basis e dar[6].

log()

Syntax: log(ausdruck)
log(ausdruck, basis)

Die log()-Funktion ist die Umkehrung der pow()-Funktion. Sie dient zur Berechnung des Logarithmus des ersten übergebenen Ausdrucks. Der Wert des zweiten Ausdrucks ist die Basis des Logarithmus. Fehlt er, ist die Basis e[7].


sqrt()

Syntax: sqrt(ausdruck)

Die sqrt()-Funktion dient zum Berechnen einer Wurzel. Der übergebene Ausdruck muss eine einheitenlose Zahl ergeben [8].

hypot()

Syntax: hypot(ausdruck, ausdruck, ausdruck, ...)

Die hypot()-Funktion dient zum Berechnen einer Vektorlänge und akzeptiert einen oder mehrere Ausdrücke. Sie bestimmt für jeden ihrer Parameter den numerischen Wert und ermittelt für diese Werte die Wurzel der Summe ihrer Quadrate. Die Typen der übergebenen Ausdrücke müssen miteinander kompatibel sein und können einheitenlos, Prozentwerte oder auch dimensionsbehaftet sein.

Mathematisch gesprochen bestimmt hypot() für N Werte die Länge eines N-dimensionalen Vektors. Bei nur zwei Koordinaten entspricht das der Anwendung des Satzes des Pythagoras[9].


Trigonometrie

Die trigonometrischen Funktionen sin(), cos() und tan() berechnen Kennzahlen zu Winkeln. Wenn Sie diese Funktionen in der Schule nicht kennengelernt haben oder sich nicht mehr erinnern, empfehlen wir zunächst die Lektüre eines Mathematikbuches oder der Wikipedia.

Der Ausdruck, den man diesen drei Funktionen übergibt, muss einen Wert vom CSS-Typ <Winkel> ergeben. Alternativ werden auch einheitenlose Zahlen akzeptiert, diese werden dann als Winkel im Bogenmaß gedeutet.

Beispielsweise führen die Schreibweisen sin(30deg), sin(1turn / 12) und sin(PI / 6) alle zum gleichen Wert, nämlich 0,5. Beachten Sie, dass Sie in der Klammer der sin()-Funktion auf calc() verzichten können.

cos()

Syntax: cos(ausdruck)

Die CSS-Funktion cos() ist eine trigonometrische Funktion, die den Kosinus eines Winkels zurückgibt, also einen einheitenlosen Wert zwischen -1 und 1. Beachten Sie für das erwartete Funktionsargument die Einleitung zu trigonometrischen Funktionen[10].

Kann verwendet werden, um die Größe einer gedrehten Box beizubehalten.

sin()

Syntax: sin(ausdruck)

Die CSS-Funktion sin() ist eine trigonometrische Funktion, die den Sinus eines Winkels zurückgibt, also einen einheitenlosen Wert zwischen -1 und 1. Beachten Sie für das erwartete Funktionsargument die Einleitung zu trigonometrischen Funktionen[11].

Ein möglicher Anwendungsfall böte sich in dem Beispiel für ein Hexagon-Grid, das Temani Afif 2022 bei css-tricks vorgestellt hat. Temani schrieb dort, er würde die folgenden Transformationen benötigen:

  translate((height + gap)*sin(  0deg), (height + gap)*cos(  0deg))
  translate((height + gap)*sin( 60deg), (height + gap)*cos( 60deg))
  translate((height + gap)*sin(120deg), (height + gap)*cos(120deg))
  translate((height + gap)*sin(180deg), (height + gap)*cos(180deg))
  translate((height + gap)*sin(240deg), (height + gap)*cos(240deg))
  translate((height + gap)*sin(300deg), (height + gap)*cos(300deg))

Das ist nicht ganz richtig, der Sinus liefert eigentlich die Y-Koordinate. Das Ergebnis wird dadurch um 90° verdreht wird. Mangels CSS-Unterstützung von Trigonometrie rechnet er das dann von Hand aus (hat aber mittlerweile bereits angemerkt, dass er sich auf CSS-Trigonometrie schon freut).

Mit Unterstützung der Trigonometriefunktionen kann man nun jedem Sechseck einen Winkel zuweisen und die Rechnung von CSS ausführen lassen. Dabei muss man beachten, dass CSS die Winkel im Uhrzeigersinn misst.

  .gallery figure:nth-of-type(1) { --angle:-120deg; }
  .gallery figure:nth-of-type(2) { --angle: -60deg; }
  .gallery figure:nth-of-type(3) { --angle: 180deg; }
  .gallery figure:nth-of-type(5) { --angle:   0deg; }
  .gallery figure:nth-of-type(6) { --angle: 120deg; }
  .gallery figure:nth-of-type(7) { --angle:  60deg; }
  .gallery figure:not(:nth-of-type(4)) {
     --radius: calc(var(--gap) + var(--imgWidth));
     transform: translate(calc(cos(var(--angle)) * var(--radius)),
                          calc(sin(var(--angle)) * var(--radius))
                         );
  }

Die Variable --radius wurde nur für leichtere Lesbarkeit eingefügt, technisch nötig ist sie nicht.

Wenn man Spaß daran hat, könnte man nun noch ein custom property --rotation mit einer @property-Deklaration als Winkel deklarieren, es auf die --angle-Werte aufaddieren und das Ganze animieren, woraufhin die Sechsecke das Zentralsechseck umkreisen würden. Da es zur Zeit (Januar 2023) noch keinen Browser gibt, der @property und CSS-Trigonometrie unterstützt, lässt sich das noch nicht an einem Live-Beispiel demonstrieren.

Ist der Einsatz von sin() und cos() hier nun unbedingt nötig? Nein, eigentlich nicht. Das gleiche Ergebnis lässt sich mit Hilfe der Technik „rotate falschrum, translate, rotate richtigrum“ erreichen:

  .gallery figure:not(:nth-of-type(4)) {
     --radius: calc(var(--gap) + var(--imgWidth));
     transform: rotate(var(--angle)) translateX(var(--radius)) rotate(calc(-1*var(--angle)));
  }

Sie erinnern sich: Transform-Funktionen werden von rechts nach links ausgeführt. Als erstes wird die <figure> also um den entgegengesetzten Winkel um ihren Mittelpunkt gedreht und dann entlang der X-Achse um den gewünschten Radius hinausgeschoben. Die zweite Drehung erfolgt nun immer noch um den ursprünglichen Mittelpunkt, die figure wird also wie an einer Stange um den gewünschten Winkel in die richtige Lage gedreht. Und da sie vorher im Mittelpunkt um den gleichen Winkel „falsch herum“ gedreht wurde, steht sie nun wieder aufrecht. Wenn Sie von diesen Überlegungen Kopfschmerzen bekommen, von sin() und cos() aber nicht, dann ist CSS-Trigonometrie für Sie genau richtig.


tan()

Syntax: tan(ausdruck)

Die CSS-Funktion tan() ist eine trigonometrische Funktion, die den Tangens eines Winkels zurückgibt, also einen einheitenlosen Wert zwischen -infinity und infinity. Beachten Sie für das erwartete Funktionsargument die Einleitung zu trigonometrischen Funktionen[12].

asin()

Syntax: asin(ausdruck)

Die CSS-Funktion asin() ist eine trigonometrische Funktion und stellt die Umkehrfunktion zu sin() dar. Wenn Sie den Sinus eines Winkels kennen (beispielsweise auf Grund eines Längenverhältnisses), können Sie mit asin() den dazu passenden Winkel bestimmen[13].

Die Funktion erwartet einen Ausdruck, der eine einheitenlose Zahl zwischen -1 und +1 liefert, und gibt dann einen Winkel von -90deg bis 90deg zurück. Andernfalls ist das Ergebnis NaN.

Leider ist der Umgang mit einem Längenverhältnis nicht so einfach, wenn Sie tatsächlich Längenangaben vorliegen haben. Der Aufruf von asin(0.5em / 1em) ist nicht möglich. Zum einen darf man in CSS nur durch einheitenlose Zahlen dividieren, und zweitens ist das Ergebnis dann eine Länge und keine einheitenlose Zahl. Es kann sein, dass CSS Units and Values Stufe 4 dieses Thema löst.

acos()

Syntax: acos(ausdruck)

Die CSS-Funktion asin() ist eine trigonometrische Funktion und stellt die Umkehrfunktion zu cos() dar. Wenn Sie den Cosinus eines Winkels kennen (beispielsweise auf Grund eines Längenverhältnisses), können Sie mit acos() den dazu passenden Winkel bestimmen[14]. Das Ergebnis ist ein Winkel von 0deg bis 180deg.

Die Funktion erwartet einen Ausdruck, der eine einheitenlose Zahl zwischen -1 und +1 liefert. Andernfalls ist das Ergebnis NaN. Beachten Sie auch die Hinweise bei asin().

atan()

Syntax: atan(ausdruck)

Die CSS-Funktion atan() ist eine trigonometrische Funktion und stellt die Umkehrfunktion zu tan() dar. Wenn Sie den Tangens eines Winkels kennen (beispielsweise auf Grund eines Längenverhältnisses), können Sie mit atan() den dazu passenden Winkel bestimmen[15].

Die Funktion erwartet einen Ausdruck, der eine einheitenlose Zahl liefert. Das Ergebnis liegt zwischen -90deg und 90deg. Als Sonderfall ist auch die Übergabe von infinity-Werten möglich: atan(infinity) ergibt 90deg und atan(-infinity) ergibt -90deg.

atan2()

Syntax: atan2(y-ausdruck, x-ausdruck)

Die CSS-Funktion atan2() ist eine trigonometrische Funktion und stellt eine erweiterte Umkehrfunktion zu tan() dar. Sie erwartet zwei Ausdrücke, die eine einheitenlose Zahl, eine Länge oder einen Prozentwert ergeben. Beide Ausdrücke müssen den gleichen Typ ergeben.

atan2() hat zwei Vorteile. Zum einen liefert atan(calc(y / x)) zwar grundsätzlich den Steigungswinkel der Geraden durch (0,0) und den Punkt (x,y), das Ergebnis ist aber nicht eindeutig. Beispielsweise führen die Punkte (1,1) und (-1,-1) zum gleichen Verhältnis y/x, der Steigungswinkel für (1,1) ist aber 45deg und für (-1,-1) -135deg. Die atan2()-Funktion löst diese Schwierigkeit, in dem sie y und x als getrennte Parameter erhält und nicht den Quotienten. Darüber hinaus ist es für x=0 auch nicht nötig, mit infinity-Werten zu arbeiten[16]. Der zweite Vorteil ist, dass atan() nur Zahlenwerte akzeptiert, während atan2() auch einheitenbehaftete Werte versteht.

Weblinks

  1. Firefox Bugzilla: Selfhtml Bugreport zu nicht funktionierenden Funktionen
  2. MDN: abs()
  3. MDN: sign()
  4. MDN: round()
  5. MDN: pow()
  6. MDN: exp()
  7. MDN: log()
  8. MDN: sqrt()
  9. MDN: hypot()
  10. MDN: cos()
  11. MDN: sin()
  12. MDN: tan()
  13. MDN: asin()
  14. MDN: asin()
  15. MDN: atan()
  16. MDN: atan2()