CSS Houdini 尝鲜

1,415 阅读4分钟

为什么需要 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

image.png 截止目前,Paint APIProperties & Values APITyped OM 三个在Blink内核的几大浏览器已经实现。其中 Paint API 已经处于 W3C 协会的『候选推荐』阶段。Safari 对前面三个特性的支持都在开发实验阶段。

总之,如果你只关注Blink内核浏览器那可以用 Paint API 、Properties & Values API 、Typed OM(甚至一部分 Layout API 、Animation Worklet)。

is houdini ready yet

CSS Proprieties and Values API

用法简介

属性-值API可以让开发者定义引擎对自定义属性的解析行为。

  1. 需要注册自定义属性
// 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:初始值
  1. 应用自定义属性
.box {
    --my-color: #333;
}
  1. 通过var()引用自定义属性
.box {
    color: var(--my-color);
}

属性-值API是提供了解析的能力(即第1步),2和3是 css自定义属性。自定义属性的兼容性更好,但是不能定义解析行为,常用在UI库换肤。

注意事项

  1. 属性一经注册无法更新注册信息,通过js也不行
  2. 与原生属性不同,解析时不会验证值的有效性。在使用时无效值不会回退到前面同名的有效值,而是回退到初始值。

示例-渐变色过渡

  • transition: background-image 1s无法奏效,因为引擎不能理解两个 linear-gradient之间有什么线性关系。
  • 缺省了注册的过程也无法奏效,因为 #000 默认是*类型,需要作为 <color> 才能线性变化。

CSS Typed OM

类比DOM,让开发者摆脱解析 document 的字符串。CSS Typed OM 也提供了结构化的 js API,而不是读写CSS字符串。

基类-CSSStyleValue

可以类比为DOM中的HTMLElement,其他的样式数据的类型都要继承 CSSStyleValue

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 构建。

  1. 在一个单独的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) {
        // 绘制
    }
});
  1. CSS.paintWorklet.addModule 载入前一步的行为。
import highlightURL from 'worklet-loader!./highlight.js';
CSS.paintWorklet.addModule(highlightURL);
  1. 在 css 中 paint(worklet name) 使用绘制行为。
.demo {
    background-image: paint(highlight);
}

应用场景:

  • 异形的边框
  • 规律复杂的纹理背景
  • 替代一部分交互弱化的 canvas 场景

精品示例

未来

还有一些未标准化的API,比如 自定义布局的 API、自定义字体的API...

由于是浏览器厂商主导,各家有一定实现的动力。比起动辄十年的委员会主导,CSS Houdini 应该不会让我们等太久,未来可期。