Potenzfunktion

Avatar of Kitty Giraudel
Kitty Giraudel am

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

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!