在客户端编译 scss 以节省网络

Compiling scss on client side to save on network

我已经看到 this example 使用 css 作为动画明星背景,并注意到在这种情况下编译的 css 明显更小,因为 sass 生成一千颗星星循环。

// n is number of stars required
@function multiple-box-shadow ($n) 
  $value: '#{random(2000)}px #{random(2000)}px #FFF'
  @for $i from 2 through $n
    $value: '#{$value} , #{random(2000)}px #{random(2000)}px #FFF'

  @return unquote($value)

这让我想知道,有没有办法在客户端生成said css?网络带宽的节省不会超过生成 css 的(微不足道的)成本吗?

我找不到此类用例的示例,网络流量的压缩是否使它无关紧要?

我不一定要专门问这个案例。更多关于如何考虑带宽与计算时间的关系(如果有的话)。对于具有在客户端使用更简洁的语法(如 Angular 中的 ngFor)生成 HTML 的方法的 js 框架也是如此。

Sass 编译器是用 C++ 编写的,因此在浏览器中 运行 它或多或少是不可能的。

相反,您可以使用 Less,运行在浏览器中运行得很好。

index.html

<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/3.9.0/less.min.js" ></script>

multiple-box-shadow.js

(this plugin is needed, because Less cannot generates random numbers by itself)

registerPlugin({
  install: function(less, pluginManager, functions) {
      functions.add('multiple-box-shadow', function(n) {
          return Array(n.value).fill().map(function() {
              var x = Math.floor(Math.random()*2000);
              var y = Math.floor(Math.random()*2000);
              return x+'px '+y+'px #FFF';
          }).join(',');
      });
  }
});

styles.less

@plugin "multiple-box-shadow";

@shadows-small:  multiple-box-shadow(700);
@shadows-medium: multiple-box-shadow(200);
@shadows-big:    multiple-box-shadow(100);

#stars {
    width: 1px;
    height: 1px;
    background: transparent;
    box-shadow: @shadows-big;
    animation: animStar 50s linear infinite;
}

对于您的具体示例:

  • styles.css:41'277 B(压缩后 5'936 B)
  • styels.less:1'856 B(压缩后 586 B)

在控制台,less输出生成时间,在我的电脑上需要100ms到200ms。

我认为在客户端编译的好处很低。 编译后的 CSS 比其源代码大的情况很少见,主要是因为 CSS 编译器缩小了它们的输出。

Wouldn't the savings on network bandwidth outweigh the (minuscule) cost of generating the css?

反对这样做的一个可能论据是,与 CSS 相比,下载较小的 SCSS 文件可能会节省带宽,但还必须向客户端提供编译器代码,与 css.

相比,(假设)超过了文件大小的差异

由于缺乏更好的例子,我假设假想的 SCSS 编译器会显示类似的行为:

For your specific example:
- styles.css: 41'277 B (5'936 B compressed)
- styels.less: 1'856 B (586 B compressed)

  • less.min.js: 167'812 B

除非浏览器预装了 SCSS-编译器,因此首先质疑 CSS 文件类型的必要性。

正如@onewaveadrian 指出的那样,尝试通过在浏览器上生成 CSS 来节省一些字节是没有意义的,而是下载 SCSS 或 LESS 编译器这样做。

但是,您可以在浏览器上仅使用 vanilla JS 生成那些 CSS 阴影,而不包括任何额外的依赖项,这将节省大量字节并且可能 运行 更快也比成熟的编译器更好。

为了让它更快,multipleBoxShadow 函数使用了一个简单的 while 循环,string concatenation and the bitwise OR operator (|) to floor numbers way faster than Math.floor() 会。

const MAX_Y_OFFSET = 2000;
const MAX_X = window.innerWidth;
const MAX_Y = window.innerHeight + MAX_Y_OFFSET;

function multipleBoxShadow(n) {
  let boxShadow = '';
  
  // Let's use a simple while loop and the bitwise OR operator (`|`) to round up values here
  // to run this as fast as possible:
  while (n--) {
    boxShadow += `,${ Math.random() * MAX_X | 0 }px ${ Math.random() * MAX_Y | 0 }px #FFF`;
  }
  
  return boxShadow.slice(1);
}

const { documentElement } = document;

documentElement.style.setProperty('--shadows-small', multipleBoxShadow(700));
documentElement.style.setProperty('--shadows-medium', multipleBoxShadow(200));
documentElement.style.setProperty('--shadows-big', multipleBoxShadow(100));
body {
  min-height: 100vh;
  background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
  overflow: hidden;
}

#stars {
  width: 1px;
  height: 1px;
  background: transparent;
  animation: animStar 50s linear infinite;
  box-shadow: var(--shadows-small);
}

#stars:after {
  content: " ";
  position: absolute;
  top: 2000px;
  width: 1px;
  height: 1px;
  background: transparent;
  box-shadow: var(--shadows-small);
}

#stars2 {
  width: 2px;
  height: 2px;
  background: transparent;
  animation: animStar 100s linear infinite;
  box-shadow: var(--shadows-medium);
}

#stars2:after {
  content: " ";
  position: absolute;
  top: 2000px;
  width: 2px;
  height: 2px;
  background: transparent;
  box-shadow: var(--shadows-medium);
}

#stars3 {
  width: 3px;
  height: 3px;
  background: transparent;
  animation: animStar 150s linear infinite;
  box-shadow: var(--shadows-big);
}

#stars3:after {
  content: " ";
  position: absolute;
  top: 2000px;
  width: 3px;
  height: 3px;
  background: transparent;
  box-shadow: var(--shadows-big);
}

@keyframes animStar {
  from {
    transform: translateY(0px);
  }
  to {
    transform: translateY(-2000px);
  }
}
<div id='stars'></div>
<div id='stars2'></div>
<div id='stars3'></div>

如您所见,我正在使用 CSS custom properties 将生成的 box-shadow 值传递给 CSS,这样我也可以在伪元素中使用它。如果你不想使用 CSS 变量,你可以使用 6 个 <div> 而不是 3 个,并像这样使用 style 属性:

document.getElementById('stars').style.boxShadow = multipleBoxShadow(700);
document.getElementById('stars2').style.boxShadow = multipleBoxShadow(700);
document.getElementById('stars3').style.boxShadow = multipleBoxShadow(200);
document.getElementById('stars4').style.boxShadow = multipleBoxShadow(200);
document.getElementById('stars5').style.boxShadow = multipleBoxShadow(100);
document.getElementById('stars6').style.boxShadow = multipleBoxShadow(100);

此外,如果动画本身的性能不够好,您可以轻松调整此代码以在 <canvas> 上绘制起点(实际上是圆形或正方形),并使用 Window.requestAnimationFrame().