几年前,如果有人提到用 JavaScript 编写 HTML 作为构建大型网站的一种方式,很多开发者会当这作不可理喻的想法,但是现在,使用 React、Vue 和 Angular 框架为组件开发的应用正在慢慢替代传统的 Web 开发。
现在 CSS-in-JS 确实也有点像当年的味道,虽然并不是唯一的解决方案,却提供了一个很大胆的想法和尝试。
对现代化的 Web 开发项目说,CSS 也是如此,CSS 做为 Web 的样式表来呈现丰富多彩的 Web 应用已经不再是唯一的选择了,我们或许应该多考虑其他的扩展性和移植性尝试未来的 CSS-in-JS。
一 CSS 的介绍
CSS(层叠样式表)是一种用来为结构化文档添加样式的计算机语言,由 W3C 定义和维护。目前最新版本是 CSS2.1,为 W3C 的推荐标准。CSS3 现在已被大部分现代浏览器支持,而下一版的 CSS4 仍在开发中。
1 模块和标准化进程
CSS Level 2 经历了 9 年的时间(从 2002 年 8 月到 2011 年 6 月)才达到 Recommendation(推荐) 状态,主要原因是被一些次要特性拖了后腿。为了加快那些已经确认没有问题的特性的标准化速度,W3C 的 CSS Working Group(CSS 工作组) 作出了一项被称为 Beijing doctrine 的决定,将 CSS 划分为许多小组件,称之为_模块_。这些模块彼此独立,按照各自的进度来进行标准化。其中一些已经是 W3C Recommendation 状态,也有一些仍是 early Working Drafts(早期工作草案)。当新的需求被肯定后, 新的模块也会同样地添加进来。
第一个 CSS 于1996年推出,下面是 CSS 版本的时间表:
2 CSS 模块状态
从形式上来说,CSS3 标准自身已经不存在了。每个模块都被独立的标准化,现在标准 CSS 包括了修订后的 CSS2.1 以及完整模块对它的扩充,模块的 level(级别)数并不一致。可以在每个时间点上为 CSS 标准定义一个 snapshots(快照),列出 CSS 2.1 和成熟的模块。
W3C 会定期的发布这些 snapshots,如 2007, 2010, 2015 或 2017。
目前为止,还没有 level 超过 3 的模块被标准化,未来应该会有所改变。不过有些模块,比如 Selectors(选择器)4 或 CSS Borders and Backgrounds(边框和背景)Level 4 早已拥有了 Editor's Draft(编辑草案),即使它们还没达到 First Published Working Draft(初次发布工作草案)状态。
3 五种 CSS 设计模式
现代化的前端开发在历史上发展了许多的 CSS 设计模式,主要发展出以下几种:
- OOCSS(Object Oriented CSS)
- SMACSS(Scalable and Modular Architecture for CSS)
- BEM(Block - Element - Modifier)
- ITCSS(Inverted Triangle Cascading Style Sheets)
- Atomic CSS
其设计的原因基本是基于这几个问题来做优化的:
- 减少选择器命名和样式的冲突
- 清晰的 CSS 整体结构
- 去除冗余代码,减少样式的体积
- 可重复利用,组件化的 CSS
- 提高 CSS 代码的可读性
4 Atomic CSS 的历史
- 2013/06/10:Brad Frost 发布了 Atomic Design 文章,在社区上有一些文章开始讨论 Atomic CSS
- 2015/01/08:《atomic design: the book》 一书发布
- 2014/10/02:atomizer 项目创建
- 2017/10/06:tailwindcss 项目创建
Tailwind CSS 和其他预编译器相比还是比较的冷门,如下图:
在 React 和 Vue 日益吞噬的 Web 开发界中,组件化的思想和工程化日渐成熟,Atomic CSS 也算是比较早推出的一个设计思想,笔者觉得 Atomic CSS 能做的事情,在 CSS-in-JS 反而能做的更好,因为 JS 框架和工具的盛行和丰富,Atomic(原子化)也是未来 CSS-in-JS 一个可以涉足的区域。
5 CSS 数学表达式
根据 CSSWG 的 draft,CSS 目前支持计算的数学表达式主要包含五大类:
- 基本算数:calc()
- 比较函数:min(), max(), clamp()
- 步进函数:round(), mod(), rem()
- 三角函数:sin(), cos(), tan(), asin(), acos(), atan(), atan2()
- 指数函数:pow(), sqrt(), hypot(), log(), exp()
日常使用中 calc() 算是最常用的,一般用来计算长宽、响应式布局等等,而比较函数在一些场景也可能会用的上,剩下的其他函数很大部分都没有机会在项目中使用的上。
6 CSS Houdini
Houdini是一组底层API,它们公开了CSS引擎的各个部分,从而使开发人员能够通过加入浏览器渲染引擎的样式和布局过程来扩展CSS。Houdini是一组API,它们使开发人员可以直接访问CSS 对象模型 (CSSOM),使开发人员可以编写浏览器可以解析为CSS的代码,从而创建新的CSS功能,而无需等待它们在浏览器中本地实现。
—— 《MDN / CSS Houdini》
如果说 CSS-in-JS 是用现有的标准用 JS 去控制、扩展和实时联动 CSS 的一套方案,那么 CSS Houdini 就相当于进阶版本的 CSS-in-JS,通过公开 CSS 引擎的各个功能,是开发人员能更好的扩展 CSS,笔者认为是不是也可以理解为 CSS Houdini 的出现也代表了现在的纯 CSS 已经很难满足现在日益丰富的 Web 应用。
CSS Houdini
CSS Parser API
这是直接地暴露出 CSS 解析器的 API接口,能够把任意 CSS 类语言解析成为一种中间类型,定义新的结构。
CSS Properties and Values API
- 定义一个用来注册新的 CSS 属性的 API。通过该 API 注册的属性必须用一种特定的解析语法书写,以定义其类型、继承行为以及初始值。
- CSS Properties and Values API reference
- CSS Properties and Values API guide
CSS Typed OM
- 可以把 CSS Typed OM 视为 CSSOM 2.0,它的目的在于解决目前模型的一些问题,并实现 CSS Parsing API 和 CSS 属性与值 API 相关的特性。
- CSS Typed OM reference
- CSS Typed OM guide
CSS Layout API
被设计来提升 CSS 扩展性的 API,该 API 能够让开发者去书写他们自己的布局算法,比如 masonry 或者 line snapping。
CSS Painting API
- 被设计来提升 CSS 扩展性的 API,该 API 允许开发者通过 paint() 方法来写 JavaScript 函数,以控制绘制页面元素的样式或内容区域。
- CSS Painting API reference
- CSS Painting API guide
Worklets
- 该 API 允许脚本独立于 JavaScript 执行环境,运行在渲染流程的各个阶段。
- Worklets 在很接近于 JS 的 Web Workers ,由渲染引擎扩展并调用。
- Worklets reference
7 CSS 预处理器 (CSS Preprocessor)
CSS 预处理器是一个能让你通过预处理器自己独有的语法来生成 CSS 的程序。市面上有很多 CSS 预处理器可供选择,且绝大多数 CSS 预处理器会增加一些原生 CSS 不具备的特性,例如代码混合,嵌套选择器,继承选择器等。这些特性让 CSS 的结构更加具有可读性且易于维护。
—— 《MDN / CSS 预处理器》
一些最流行的 CSS 预处理器:
- PostCSS:2013/11/04
- Less:2009
- SASS:2006/11/28
- Stylus:2010/12/29
图中看到 PostCSS 的下载量一直遥遥领先其他 CSS 预处理器,PostCSS 比较大的优势在于社区有很多插件可以使用,相当于 CSS 届的 Babel,常见 PostCSS 插件如下:
- Autopre?xer:自动补全浏览器私有前缀
- precss:CSS 预处理(整合 Sass、LESS 或 Stylus 功能,语法基本和 Sass 的相同)
- postcss-import:通过 @import,整合多个 CSS 文件
- css-mqpacker:将相同的 CSS 媒体查询规则合并为一个
- cssnano:压缩 CSS 文件
- postcss-color-rgba-fallback:给 rgba 颜色创建降级方案(添加备用颜色)
- postcss-opacity:给 opacity 提供降级方案(给 IE 浏览器添加滤镜属性)
- node-pixrem:让 IE8 ?持 rem 单位
- postcss-pseudoelements:将伪元素的 :: 转换为 : ( IE8 不不?支持 ::)
如果一定需要使用 CSS 预处理器,可能 PostCSS 是最好的选择之一,当然,也是需要看实际你项目的整体方案来选择。
8 CSS-in-JS VS CSS Preprocessor
在 Google Trends 中我们可以看到 2014 年后 CSS-in-JS 的趋势就逐渐超越了 CSS 预处理器,这在一方面也说明了开发人员在 CSS-in-JS 上有着很大兴趣。
二 CSS-in-JS 的介绍
CSS-in-JS是一种样式化技术,其中 JavaScript 用于样式化组件。解析此 JavaScript 时,将生成 CSS(通常作为