Während Sass bei arithmetischen Berechnungen sehr hilfreich ist, mangelt es ihm etwas an mathematischen Hilfsfunktionen. Es gibt seit fast 3 Jahren ein offenes Problem im offiziellen Repository, das nach weiteren mathematischen Funktionen fragt.
Einige Drittanbieter wie Compass oder SassyMath bieten erweiterte Unterstützung für mathematische Funktionen, aber es handelt sich um externe Abhängigkeiten, die (sollten?) vermieden werden könnten.
Eine der beliebtesten Anfragen in dieser Angelegenheit ist eine Potenzfunktion oder sogar ein Exponentierungsoperator. Leider gibt es in Sass noch keine Unterstützung dafür, und obwohl dies noch aktiv diskutiert wird, ist es unwahrscheinlich, dass es sehr bald geschieht.
In der Zwischenzeit erweist sich die Fähigkeit, eine Zahl mit einer bestimmten Potenz zu potenzieren, in CSS als sehr nützlich. Hier sind einige Beispiele, wo dies nützlich wäre
- um die Leuchtdichte einer Farbe zu bestimmen;
- um eine Zahl auf eine bestimmte Anzahl von Dezimalstellen zu runden;
- um etwas (inverse) Trigonometrie durchzuführen…
Sass-Implementierung
Glücklicherweise ist es möglich (und ziemlich einfach), eine Potenzfunktion mit nichts als Sass zu erstellen. Alles, was wir brauchen, ist eine Schleife und einige grundlegende mathematische Operatoren (wie * und /).
Positive ganzzahlige Exponenten
Unsere Funktion (genannt pow) in ihrer kleinsten Form würde so aussehen
@function pow($number, $exponent) {
$value: 1;
@if $exponent > 0 {
@for $i from 1 through $exponent {
$value: $value * $number;
}
}
@return $value;
}
Hier ist ein Beispiel
.foo {
width: pow(20, 2) * 1px; // 400px
}
Positive oder negative ganzzahlige Exponenten
Allerdings funktioniert sie nur mit einem positiven `$power`-Argument. Das Zulassen negativer Exponenten wäre nicht so schwer, wir brauchen nur eine kleine zusätzliche Bedingung
@function pow($number, $exponent) {
$value: 1;
@if $exponent > 0 {
@for $i from 1 through $exponent {
$value: $value * $number;
}
} @else if $exponent < 0 {
@for $i from 1 through -$exponent {
$value: $value / $number;
}
}
@return $value;
}
Hier ist ein Beispiel
.foo {
width: pow(10, -2) * 1px; // 0.0001px
}
Positive oder negative Exponenten
Was ist nun, wenn wir nicht-ganzzahlige Exponenten wollen? Wie zum Beispiel 4.2? Die Wahrheit ist, dass es wirklich nicht einfach ist. Es ist immer noch machbar, aber es erfordert mehr als nur eine Schleife und ein paar Operationen.
Dies wurde im Bourbon-Repository gemacht, um die modular-scale(..)-Funktion des Frameworks zu vervollständigen (obwohl sie abgelehnt wurde). Hier ist der Code
@function pow($number, $exponent) {
@if (round($exponent) != $exponent) {
@return exp($exponent * ln($number));
}
$value: 1;
@if $exponent > 0 {
@for $i from 1 through $exponent {
$value: $value * $number;
}
} @else if $exponent < 0 {
@for $i from 1 through -$exponent {
$value: $value / $number;
}
}
@return $value;
}
@function factorial($value) {
$result: 1;
@if $value == 0 {
@return $result;
}
@for $index from 1 through $value {
$result: $result * $index;
}
@return $result;
}
@function summation($iteratee, $input, $initial: 0, $limit: 100) {
$sum: 0;
@for $index from $initial to $limit {
$sum: $sum + call($iteratee, $input, $index);
}
@return $sum;
}
@function exp-maclaurin($x, $n) {
@return (pow($x, $n) / factorial($n));
}
@function exp($value) {
@return summation('exp-maclaurin', $value, 0, 100);
}
@function ln-maclaurin($x, $n) {
@return (pow(-1, $n + 1) / $n) * (pow($x - 1, $n));
}
@function ln($value) {
$ten-exp: 1;
$ln-ten: 2.30258509;
@while ($value > pow(10, $ten-exp)) {
$ten-exp: $ten-exp + 1;
}
@return summation(ln-maclaurin, $value / pow(10, $ten-exp), 1, 100) + $ten-exp * $ln-ten;
}
Weitere Überlegungen
Nun, das war intensiv. Wenn Sie Unterstützung für nicht-ganzzahlige Exponenten (wie 4.2) benötigen, empfehle ich Ihnen, eine externe Abhängigkeit zu verwenden, die dies bietet (wie z. B. sass-math-pow), anstatt all diesen Code in Ihr Projekt aufzunehmen. Nicht, dass es an sich schlecht ist, aber es ist nicht wirklich die Aufgabe Ihres Projekts, eine so große Menge an nicht-eigenem Füllcode zu hosten (deshalb haben wir Paketmanager).
Beachten Sie auch, dass all diese Operationen für eine so dünne Schicht wie Sass recht intensiv sind. An diesem Punkt, und wenn Ihr Design auf fortgeschrittenen mathematischen Funktionen basiert, ist es wahrscheinlich besser, die Implementierung dieser Helfer von der oberen Schicht (Node.js, Ruby usw.) durch ein Plugin-System (Eyeglass, Ruby gem usw.) nach Sass zu verlagern.
Aber für den einfachen pow(..)-Gebrauch kann ich die einfachen Versionen nur wärmstens empfehlen!
Wie kann ich die $number als dynamischen VW-Wert setzen?
Hier ist eine Hilfsfunktion zur Behandlung von Einheiten
Sie entfernt zuerst die Einheiten und fügt sie dann dem Ergebnis wieder hinzu.
Nur eine kurze Anmerkung, die Funktion für nicht-ganzzahlige Exponenten zeigt Folgendes an
Um dies zu beheben, suchen Sie die beiden Summationsaufrufe und ändern Sie die ersten Parameter entsprechend.
Warum sollten externe Sass-Abhängigkeiten vermieden werden? Funktionen und Mixins aus externen Bibliotheken werden nicht in den kompilierten CSS-Code aufgenommen, sodass der Benutzer nicht mehr HTTP-Anfragen und größere Download-Dateien hat. Ich verstehe, warum dies für einige Leute bei JavaScript-Bibliotheken ein Problem darstellt, die möglicherweise die Optimierung beeinträchtigen, aber warum halten Sie dies bei Sass für etwas, das vermieden werden sollte?
Ich verwende eine Version dieser komplexen pow()-Funktionen zur Berechnung der Farbleuchtdichte. Ich musste in der Lage sein, eine Zahl mit 2,4 zu potenzieren.
Es funktioniert, aber es ist langsam für diese mathematisch-intensiven komplexen Berechnungen. Gibt es eine Möglichkeit, das Sass-Caching manuell zu nutzen, wenn es einen Farbvergleich durchläuft, der sich nicht geändert hat? Ich denke an Entwickler, die lange
--watch-Kompilierungszeiten abwarten, wenn sich der Inhalt dieser Funktion nicht geändert hat. Es besteht keine Notwendigkeit, sie alle neu zu kompilieren.