是什么
CSS-in-JS是一种技术(technique),而不是一个具体的库实现(library)。简单来说CSS-in-JS就是将应用的CSS样式写在JavaScript文件里面,而不是独立为一些.css
,.scss
或者less
之类的文件,这样你就可以在CSS中使用一些属于JS的诸如模块声明,变量定义,函数调用和条件判断等语言特性来提供灵活的可扩展的样式定义。值得一提的是,虽然CSS-in-JS不是一种很新的技术,可是它在国内普及度好像并不是很高,它当初的出现是因为一些component-based
的Web框架(例如React,Vue和Angular)的逐渐流行,使得开发者也想将组件的CSS样式也一块封装到组件中去以解决原生CSS写法的一系列问题。还有就是CSS-in-JS在React社区的热度是最高的,这是因为React本身不会管用户怎么去为组件定义样式的问题,而Vue和Angular都有属于框架自己的一套定义样式的方案。
本文将通过分析CSS-in-JS这项技术带来的好处以及它存在的一些问题来帮助大家判断自己是不是要在项目中使用CSS-in-JS。
不同的实现
实现了CSS-in-JS的库有很多,据统计现在已经超过了61种。虽然每个库解决的问题都差不多,可是它们的实现方法和语法却大相径庭。从实现方法上区分大体分为两种:唯一CSS选择器和内联样式(Unique Selector VS Inline Styles)。接下来我们会分别看一下对应于这两种实现方式的两个比较有代表性的实现:styled-components和radium。
Styled-components
Styled-components 应该是CSS-in-JS最热门的一个库了,到目前为止github的star数已经超过了27k。通过styled-components,你可以使用ES6的标签模板字符串语法(Tagged Templates)为需要styled
的Component定义一系列CSS属性,当该组件的JS代码被解析执行的时候,styled-components会动态生成一个CSS选择器,并把对应的CSS样式通过style标签的形式插入到head标签里面。动态生成的CSS选择器会有一小段哈希值来保证全局唯一性来避免样式发生冲突。
CSS-in-JS Playground是一个可以快速尝试不同CSS-in-JS实现的网站,上面有一个简单的用styled-components实现表单的例子:
从上面的例子可以看出,styled-components不需要你为需要设置样式的DOM节点设置一个样式名,使用完标签模板字符串定义后你会得到一个styled好的Component,直接在JSX中使用这个Component就可以了。接着让我们打开DevTools查看一下生成的CSS:
从上面DevTools可以看出styled的Component样式存在于style标签内,而且选择器名字是一串随机的哈希字符串,这样其实实现了局部CSS作用域的效果(scoping styles),各个组件的样式不会发生冲突。除了styled-components,采用唯一CSS选择器做法的实现还有:jss,emotion,glamorous等。
Radium
Radium是由FormidableLabs创建的在github上有超过7.2k star的CSS-in-JS库。Radium和styled-components的最大区别是它生成的是标签内联样式(inline styles)。由于标签内联样式在处理诸如media query
以及:hover
,:focus
,:active
等和浏览器状态相关的样式的时候非常不方便,所以radium为这些样式封装了一些标准的接口以及抽象。
再来看一下radium在CSS-in-JS Playground的例子:
从上面的例子可以看出radium定义样式的语法和styled-components有很大的区别,它要求你使用style属性为DOM添加相应的样式。打开DevTools查看一下radium生成的CSS:
从DevTools上面inspect的结果可以看出,radium会直接在标签内生成内联样式。内联样式相比于CSS选择器的方法有以下的优点:
- 自带局部样式作用域的效果,无需额外的操作
- 内联样式的权重(specificity)是最高的,可以避免权重冲突的烦恼
- 由于样式直接写在HTML中,十分方便开发者调试
其他区别
不同的CSS-in-JS实现除了生成的CSS样式和编写语法有所区别外,它们实现的功能也不尽相同,除了一些最基本的诸如CSS局部作用域的功能,下面这些功能有的实现会包含而有的却不支持:
- 自动生成浏览器引擎前缀 - built-in vendor prefix
- 支持抽取独立的CSS样式表 - extract css file
- 自带支持动画 - built-in support for animations
- 伪类 - pseudo classes
- 媒体查询 - media query
- 其他
想了解更多关于不同CSS-in-JS的对比,可以看一下Michele Bertoli整理的不同实现的对比图。
好处
看完了一些不同的实现,大家应该对CSS-in-JS一些基本的概念和用法有了大概的理解&#