51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

style9:JS内建CSS

去年4月,Facebook透露了其重大的新设计。一个雄心勃勃的项目,它是对拥有大量用户的大型站点的重建。为此,他们使用了已创建并开源的多种技术,例如React,GraphQL,Relay和一个名为stylex的新CSS-in-JS库。

这个新库位于Facebook内部,但是他们已经共享了足够的信息,从而使开源实现style9成为可能。

为什么要使用另一个CIJ库?

已经有很多CSS-in-JS(CIJ)库,因此可能不明显为什么需要另一个。正如Christopher Chedeau所述,style9具有与所有其他CIJ解决方案相同的优势,包括范围选择器,无效代码消除,确定性解析以及在CSS和JavaScript之间共享值的能力。

但是,有几件事使style9变得独特。

最少的运行时间

尽管样式是用JavaScript定义的,但编译器会将它们提取到常规CSS文件中。这意味着最终的JavaScript文件中没有提供样式。剩下的只有最终的类名,最小化运行时将有条件地应用它们,就像您通常会做的那样。这样可以减少代码束,减少内存使用量,并加快渲染速度。

由于这些值是在编译时提取的,因此不能使用真正的动态值。值得庆幸的是,这些不是很常见,并且由于它们是唯一的,因此不必内联定义。更常见的是有条件地应用样式,当然可以支持样式。多亏了babel,局部常量和数学表达式也是如此path.evaluate。

原子输出

由于style9的工作原理,每个属性声明都可以通过单个属性制成自己的类。因此,例如,如果我们opacity: 0在代码中的多个地方使用它,则它将仅在生成的CSS中存在一次。这样做的好处是CSS文件随着唯一声明的数量而不是声明总数的增加而增长。由于大多数属性被多次使用,因此这可能导致CSS文件大大缩小。例如,Facebook的旧主页使用了413 KB的压缩CSS。重新设计的所有页面使用74 KB 。同样,较小的文件大小可带来更好的性能。

1.jpg

有人可能会抱怨,生成的类名不是语义的,它们是不透明的,并且忽略了级联。这是真的。我们将CSS视为编译目标。但是有充分的理由。通过质疑以前假定的最佳实践,我们可以改善用户和开发人员的体验。

此外,style9还具有许多其他出色的功能,包括:使用TypeScript的键入样式,未使用的样式消除,使用JavaScript变量的功能以及对媒体查询,伪选择器和关键帧的支持。

使用方法

首先,像往常一样安装它:

npm install style9

style9具有适用于Rollup,Webpack,Gatsby和Next.js的插件,它们均基于Babel插件。存储库中提供了有关如何使用它们的说明。在这里,我们将使用webpack插件。

const Style9Plugin = require('style9/webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      // This will transform the style9 calls
      {
        test: /\.(tsx|ts|js|mjs|jsx)$/,
        use: Style9Plugin.loader
      },
      // This is part of the normal Webpack CSS extraction
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  plugins: [
    // This will sort and remove duplicate declarations in the final CSS file
    new Style9Plugin(),
    // This is part of the normal Webpack CSS extraction
    new MiniCssExtractPlugin()
  ]
};

定义样式

创建样式的语法与其他库非常相似。我们从调用style9.create样式对象开始:

import style9 from 'style9';

const styles = style9.create({
  button: {
    padding: 0,
    color: 'rebeccapurple'
  },
  padding: {
    padding: 12
  },
  icon: {
    width: 24,
    height: 24
  }
});

因为所有声明都将导致原子类,所以诸如flex: 1和之类的速记均background: blue无效,因为它们设置了多个属性。可以是属性可以被扩展,例如padding,margin,overflow等将自动转换到其普通写法变体。如果使用TypeScript,则在使用不受支持的属性时会出现错误。

解析样式

要生成一个类名,我们现在可以调用所返回的函数style9.create。它接受我们要使用的样式的键作为参数:

const className = styles('button');

该函数的工作方式是,右侧的样式优先,并且将与左侧的样式合并,例如Object.assign。以下内容将导致元素的填充为12px,并带有rebeccapurple文本。

const className = styles('button', 'padding');

我们可以使用以下任何一种格式有条件地应用样式:

// logical AND
styles('button', hasPadding && 'padding');
// ternary
styles('button', isGreen ? 'green' : 'red');
// object of booleans
styles({
  button: true,
  green: isGreen,
  padding: hasPadding
});

这些函数调用将在编译期间删除,并替换为直接字符串连接。上面代码的第一行将替换为'c1r9f2e5 ' + hasPadding ? 'cu2kwdz ' : ''。没有留下任何运行时。

组合样式

我们可以通过使用属性名称访问样式对象并将其传递给来扩展样式对象style9。

const styles = style9.create({ blue: { color: 'blue; } });
const otherStyles = style9.create({ red: { color: 'red; } });

// will be red
const className = style9(styles.blue, otherStyles.red);

就像函数调用一样,右侧的样式优先。但是,在这种情况下,无法静态解析类名称。而是将属性值替换为类,并在运行时将其连接。这些属性像以前一样被添加到CSS文件中。

总结

CSS-in-JS的好处是非常真实的。也就是说,将样式嵌入代码中时,我们要付出一定的性能代价。通过在构建期间提取值,我们可以兼得两全。我们可以通过将样式与标记一起定位以及使用现有JavaScript基础结构的能力而受益,同时还能够生成最佳的样式表。


如果style9对您来说听起来很有趣,请查看回购协议并尝试一下。如果您有任何问题,请随时提出问题或取得联系。


赞(0)
未经允许不得转载:工具盒子 » style9:JS内建CSS