为什么需要 CSS Houdini
1. 为引擎分忧
从『UI稿』到『前端页面』的距离是多少?
大概隔着一个 can i use 吧~
即使再好看的样式,浏览器的css引擎没有实现我们也支持不了。假如我们可以参与到浏览器对CSS的解析和渲染中,也就有可能实现异形边框、渐变动画... CSS Houdini 不包含新奇的效果,而是交给开发者来实现。
2. CSS ployfill
由于JS是一门动态语言,可以『自己解释自己』,可以通过 polyfill 向下兼容。CSS 还没有这能力。受JS启发,Apple、Google、Mozilla等浏览器厂商的工程师成立的工作组 ———— Houdini。在支持 CSS Houdini 的浏览器之间,CSS 的差异将被抹平。
简介
CSS Houdini 是一组扩展CSS解析、渲染能力的API
- Parser API
- Properties & Values API
- Typed OM
- Layout API
- Paint API
- Worklet
截止目前,Paint API 、Properties & Values API 、Typed OM 三个在Blink内核的几大浏览器已经实现。其中 Paint API 已经处于 W3C 协会的『候选推荐』阶段。Safari 对前面三个特性的支持都在开发实验阶段。
总之,如果你只关注Blink内核浏览器那可以用 Paint API 、Properties & Values API 、Typed OM(甚至一部分 Layout API 、Animation Worklet)。
CSS Proprieties and Values API
用法简介
属性-值API可以让开发者定义引擎对自定义属性的解析行为。
- 需要注册自定义属性
// js
window.CSS.registerProperty({
name: '--my-color',
syntax: '<color>',
inherits: false,
initialValue: '#000',
});
// css
@property --my-color {
syntax: '<color>';
inherits: false;
initial-value: #000;
}
通过 javascript window.CSS.registerProperty 和 css @property 都可以注册自定义属性。
- name:要求以
--开头,同一文档内的自定义属性处于同一命名空间。 - syntax:默认为
*, 常见值有<color>(#000)、<length>(2px)、<number>(20%)、<time>(2s),详细参见css基本数据类型 - inherits:是否继承
- initial-value:初始值
- 应用自定义属性
.box {
--my-color: #333;
}
- 通过
var()引用自定义属性
.box {
color: var(--my-color);
}
属性-值API是提供了解析的能力(即第1步),2和3是 css自定义属性。自定义属性的兼容性更好,但是不能定义解析行为,常用在UI库换肤。
注意事项
- 属性一经注册无法更新注册信息,通过js也不行
- 与原生属性不同,解析时不会验证值的有效性。在使用时无效值不会回退到前面同名的有效值,而是回退到初始值。
示例-渐变色过渡
transition: background-image 1s无法奏效,因为引擎不能理解两个 linear-gradient之间有什么线性关系。- 缺省了注册的过程也无法奏效,因为
#000默认是*类型,需要作为<color>才能线性变化。
CSS Typed OM
类比DOM,让开发者摆脱解析 document 的字符串。CSS Typed OM 也提供了结构化的 js API,而不是读写CSS字符串。
基类-CSSStyleValue
可以类比为DOM中的HTMLElement,其他的样式数据的类型都要继承 CSSStyleValue:
- CSSImageValue:图像数据,比如
url(xxx.png) - CSSKeywordValue:枚举数据,比如
flex、inline-block - CSSNumericValue:数值数据,比如
10px、20% - CSSPositionValue:位置数据,比如
top left、10px 20px - CSSTransformValue:transform值的数据,比如
width 1s - CSSUnparsedValue:自定义属性值
Typed OM对于样式的读写将使用到这些数据类型。只需关注自己操作的属性对应值类型即可(比如读写width要用到CSSNumericValue)。
StylePropertyMap
StylePropertyMap 是操作样式的API
- attributeStyleMap:dom style属性上的样式集合,可读写
- computedStyleMap:经过计算的,包含内联和link的样式,只读
Paint API
开发者可以通过 paint() 方法书写 JavaScript 函数,来控制绘制元素的背景、边框或者内容区域。
API 核心是完成与 paint worklet 交互。worklet 与 web worker 类似,可理解为浏览器提供的一系列完成特定任务的 web worker 。webpack4 的项目需配合 woklet-loader 实现 paint worklet 构建。
- 在一个单独的js文件中,通过
registerPaint注册一个 paint worklet 的行为。确保第一个参数的 worklet name 唯一,后面将在 css 中通过 name 调用绘制行为。
registerPaint('highlight', class Highlight {
// 画布配置
static get contextOptions() {
return {alpha: true};
}
// 声明需要用到上下文的属性
static get inputProperties() {
return ['--my-color'];
}
paint(ctx, size, properties, args) {
// 绘制
}
});
CSS.paintWorklet.addModule载入前一步的行为。
import highlightURL from 'worklet-loader!./highlight.js';
CSS.paintWorklet.addModule(highlightURL);
- 在 css 中
paint(worklet name)使用绘制行为。
.demo {
background-image: paint(highlight);
}
应用场景:
- 异形的边框
- 规律复杂的纹理背景
- 替代一部分交互弱化的 canvas 场景
未来
还有一些未标准化的API,比如 自定义布局的 API、自定义字体的API...
由于是浏览器厂商主导,各家有一定实现的动力。比起动辄十年的委员会主导,CSS Houdini 应该不会让我们等太久,未来可期。