虽然 Sass 在算术运算方面非常有用,但在数学辅助函数方面略显不足。在官方仓库中,已经有一个关于请求更多与数学相关的函数的开放性问题 存在了将近 3 年。
一些第三方供应商,如Compass 或SassyMath,提供了对数学功能的高级支持,但它们是外部依赖项,应该(最好)避免。
关于此问题,最受欢迎的请求之一是幂函数,甚至是一个指数运算符。不幸的是,Sass 仍然不支持此功能,尽管它仍在积极讨论中,但短期内不太可能实现。
与此同时,能够将一个数字提升到某个幂在 CSS 中非常有用。以下是一些它可以派上用场的例子:
Sass 实现
幸运的是,我们只需使用 Sass 就可以创建幂函数(这非常简单)。我们只需要一个循环和一些基本的数学运算符(如 *
和 /
)。
正整数指数
我们函数(命名为 pow
)的最简形式如下所示:
@function pow($number, $exponent) {
$value: 1;
@if $exponent > 0 {
@for $i from 1 through $exponent {
$value: $value * $number;
}
}
@return $value;
}
这是一个例子:
.foo {
width: pow(20, 2) * 1px; // 400px
}
正整数或负整数指数
但是它只适用于正数的 $power
参数。允许负指数并不难,我们只需要一个小的额外条件:
@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;
}
这是一个例子:
.foo {
width: pow(10, -2) * 1px; // 0.0001px
}
正数或负数指数
现在,如果我们想要非整数指数呢?例如 4.2
?事实是,这真的不容易。它仍然可行,但需要不仅仅是循环和几个运算。
这已经在Bourbon 仓库中完成,以便完善框架中的 modular-scale(..)
函数(尽管已被拒绝)。代码如下:
@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;
}
进一步的考虑
好吧,这很复杂。如果你碰巧需要对非整数指数(如 4.2
)的支持,我建议你使用提供此功能的外部依赖项(如sass-math-pow),而不是将所有这些代码包含在你的项目中。这本身并不是一件坏事,但你的项目并不真正负责托管如此大量的非作者编写的 polyfill 代码(这就是我们使用包管理器的理由)。
另请注意,所有这些操作对于像 Sass 这样薄的一层来说都非常密集。此时,如果你的设计依赖于高级数学函数,那么最好通过插件系统(Eyeglass、Ruby gem 等)将这些辅助函数的实现从上层(Node.js、Ruby 等)传递到 Sass。
但是对于基本的 pow(..)
用法,我强烈推荐简单的版本!
我如何将 $number 设置为动态的 VW 值?
这是一个处理单位的辅助函数:
它首先去除单位,然后将其添加回结果中。
只是一个快速说明,非整数指数函数显示以下内容:
要解决此问题,请找到两个求和调用并相应地更改第一个参数。
为什么要避免外部 Sass 依赖项?来自外部库的函数和混入不会包含在编译后的 css 中,因此用户不必下载更多 HTTP 请求和更大的文件大小。我理解为什么有些人会担心 JavaScript 库可能会降低优化,但你为什么认为在 Sass 中应该避免这种情况?
我正在使用这些复杂的 pow() 函数的版本来计算颜色亮度。我需要能够将一个数字提升到 2.4 次幂。
它可以工作,但对于这些数学密集型复杂计算来说速度很慢。当颜色比较没有改变时,有没有办法手动利用 SASS 缓存?我正在考虑开发人员在该函数的内容没有改变时等待漫长的
--watch
编译时间。无需再次编译它们。