前言
2021年,vanilla-extract
作为黑马登顶了 css-in-js
满意度榜首(虽然使用率仅为1%),号称是一个类型安全、高度兼容 TS 场景的库,国内相关讨论还很少,稍微看了一下还挺好用的。
介绍
官方文档:https://vanilla-extract.style/documentation/
打开vanilla-extract
官网文档,里面已经罗列了他的那些优点。作为一个如果使用 css-in-js
会首选styled-components
的我来说,比较关注的点主要是:
- All styles generated at build time
- Type-safe styles via CSSType.
这两点说白了就是,零运行时且支持typescript
。
- 零运行时:
vanilla-extract
会在编译时期,编译出css
modules
值和css
内容,不需要带任何运行时内容到生产环境,相对来说运行速度更高,产物体积更小; - typescript:支持
typescript
类型检查,CSS安全;
目前,业界大多数相关竞品如 styled-components
就是一个运行时方案且基于标签模板进行书写,主要基于stylis
解析器解析,如果频繁更新props
还会造成style
标签大量插入到head
里。
安装
Webpack 环境下,需要同时安装 @vanilla-extract/css
与 @vanilla-extract/webpack-plugin
插件:
yarn add @vanilla-extract/css @vanilla-extract/webpack-plugin
安装完成后,修改 Webpack 配置:
代码语言:javascript复制const { VanillaExtractPlugin } = require('@vanilla-extract/webpack-plugin')
module.exports = {
entry: './src/index.js',
// ....
plugins: [new VanillaExtractPlugin()]
};
这里可以看见,当我们使用 vanilla-extract
时,需要安装两个库:
@vanilla-extract/css
:开发核心库,基于该库进行项目业务样式开发;@vanilla-extract/webpack-plugin
:webpack
插件。前面也提及了vanilla-extract
是一个零运行的库,主要是通过该插件处理。- 通过增加
webpack
配置项,对相关后缀文件使用自定义的@vanilla-extract/webpack-plugi/loader
进行处理。 - 在其内部通过
eval
库在编译时先执行得到className
结果,避免在运行时执行过程; - 再移除
@vanilla-extract/css
库,使其不会影响到生产环境下js
包体大小;
- 通过增加
构建样式API
这里只会对vanilla-extract
比较核心的构建样式相关几个API提及,其他API
可以直接前往官网查看。
style
代码语言:javascript复制import { style } from '@vanilla-extract/css';
export const parentClass = style({
background: 'red',
':hover': {
background: 'blue',
},
});
export const childClass = style({
selectors: {
'&:nth-child(2n)': {
background: '#fafafa',
},
[`${parentClass} &`]: {
color: 'pink',
},
},
});
代码语言:javascript复制import { childClass, parentClass } from './index.styles.css';
const Demo = () => (
<div className={parentClass}>
<div className={childClass}>DEMO1</div>
<div className={childClass}>DEMO2</div>
<div className={childClass}>DEMO3</div>
</div>
);
export default Demo;
这个简单的demo
我相信,看几下就已经明白是怎么使用了。但是需要理解的地方是,为了提高可维护性,「每个样式块只能针对某个元素(或者说是使用这个样式块的元素)」。那么在上述代码里的selectors
而言,「其目标必须是」**&
**(也就是自身元素)而不能是其他元素。例如:`${parentClass} &`
是OK的,但是`& div`
是不允许的。这样的设计,我觉得更是一种职责分离吧,每个样式块都针对某个元素,那么对于项目而言,样式的可维护性就大大提高了,相比于其他css
in
js
(styled-components)就不容易出现样式冗余的问题。对于一些特殊情况,比如:在写styled-components
我们会利用其包裹arco
组件(或是其他组件),然后对其内部元素样式进行覆写或是新增。
const StyledSelect = styled(Select)`
div {
color: red;
}
`
那么在vanilla-extract
样式块里是不能直接做到的,因为每个样式块都是针对某个元素,是不能直接通过该样式块,直接对其兄弟元素、子元素进行样式调整。但是,对于这种情况,是可以使用另一个APIglobalStyle
进行开发。
globalStyle
顾名思义,就是全局样式API。但是因为本身vanilla-extract
走css module
,每个className都是独一无二,那么通过globalStyle
来对其子元素进行样式调整覆盖完全是可行的。
import { style, globalStyle } from '@vanilla-extract/css';
export const parentClass = style({});
globalStyle(`${parentClass} > div`, {
color: 'red'
});
const Demo = () => (
<div className={parentClass}>
<Select/>
</div>
)
相比于 Styled-components 的优点
- 零运行时;
- 样式开发走Typescript安全类型;
- style设计职责分离;(当然,styled-components也是可以的,只是完全取决于看开发者)
- ...
总结
目前了解下来,vanilla-extract
是一个总体还不错的css
in
js
库,虽然目前使用率比较低,但是后续厂商平台项目会考虑在一些地方使用看看效果(毕竟不会增大js体积)。