Summary
Houdini是CSS的发展方向之一,让开发者拥有操作CSS引擎的能力,创建自定义的CSS。让我们从自定义button样式开始,快速上手Houdini。
Houdini是什么?
为什么需要它 - CSS的polyfill
相比保守的CSS,JS则可以更加自由地定义各种属性和方法,实现各种抽象的逻辑。在近几年的飞速发展中,开发者可以激进地使用最新的JS特性,并通过一系列ployfill解决浏览器的兼容问题。CSS则与之相反,一直没有开放CSS引擎的API。这使得开发者不得不十分谨慎地使用CSS,避免各种浏览器兼容性问题。
为了加速CSS在社区的演进,Houdini作为一个新的W3C工作组,他们希望提供一套API,来让开发者拥有操作CSS引擎的能力,进而创建自定义的CSS。Houdini工作组众星云集,Mozilla,Apple,Opera,Microsoft,HP,Intel和Google的工程师都参与其中。目前,Houdini还是一份草案,这里展示了详细内容。
Houdini的核心概念
从W3C的草案中,我们能够发现Houdini计划提供这几种API/Class:Layout API,Painting API,Properties & Values API,Worklets,Typed OM,Box Tree API和Parser API。他们的兼容性可以在ishoudini查看。目前为止,Chrome (Canary)是兼容性最好的浏览器。
本文以目前支持度最好的CSS Paint API为例,着重介绍两个核心概念:Worklets和CSS Paint API。
Worklets
Worklets是一个在浏览器rendering pipeline运行脚本的Class,它独立于JS主线程。这听起来和Web Workers很像,但它们的目标和区别在于
- Web Workers作为一个后台运行的线程,完成一些长时间的工作而且不会阻塞主线程。它应该长时间存活,并消耗相对较多的CPU、内存。
- Worklets是个受渲染引擎控制的轻量化、短生命周期线程,开发者并不知道这个线程的具体情况,并且同一类Worklets可能有多个实例,并且直接注册在Global scope。
可以认为Worklets是个抽象类,开发者需要实现它的子类,例如Paint Worklet。同时,仅定义Worklets是没有任何效果的,需要把它注册到Global Scope上。在下面的CSS Paint API我们能看到一个具体的例子。
CSS Paint API
CSS Paint API用来绘制一个CSS box的background,content和highlight。首先定义一个Paint Worklet,它是个JS Class。接着用registerPaint函数注册到Global Scope。最后,我们在Demo中使用CSS.paintWorklet.addModule函数import这个JS Module。完成这3步后,就能在CSS中使用paint函数了,例如:background: paint('my-background')。
Paint Worklet用paint函数用来绘制图案,它有4个参数
- ctx: 一个PaintRenderingContext2D实例,canvas的大部分功能都能够使用
- size: 一个PaintSize实例,包含元素的width, height
- styleMap: 一个StylePropertyMapReadOnly实例,主要用于读取DOM的style property
- args: paint函数的输入参数,例如在CSS中声明:background: paint('my-background', red),red就是一个输入参数
inputProperties函数返回自定义的CSS Property Name,例如'--my-prop',不在此声明的Property会被渲染引擎过滤,即无法在styleMap中读取。
inputArguments函数返回自定义的CSS Property Value的格式,例如'<color>',缺省时不做检查,可被看成string。这里是目前支持的格式。
class Button {
static get inputArguments() { return ['<color>'] }
static get inputProperties() { return ['--my-prop'] }
paint(ctx, size, styleMap, args) {
// paint function do drawing on the ctx, just like canvas
}
}
// this is the critical point
// registerPaint function is valid with CSS Paint API
registerPaint('button', Button)
复制代码
快速上手 - 自定义button
了解了Worklets和CSS Paint API后,我们就能开始自定义自己的button样式。
定义Button Worklet
先定义Button Worklet。它定义了一个custom property: --my-bg-color,接着在paint函数中,调用drawBezierCurve函数画了一条贝塞尔曲线。
class Button {
constructor() {
this.width = 0;
this.height = 0;
this.bgColor = "black";
}
static get inputProperties() {
return ["--my-bg-color"];
}
paint(ctx, size, styleMap) {
const { width, height } = size;
this.width = width;
this.height = height;
this.bgColor = styleMap
.get("--my-bg-color")
.toString()
.trim();
this.drawBezierCurve(ctx);
}
drawBezierCurve(ctx) {
ctx.fillStyle = this.bgColor;
ctx.beginPath();
ctx.moveTo(0, this.height);
ctx.lineTo(this.width / 4, this.height);
ctx.bezierCurveTo(
this.width / 3,
this.height,
this.width / 2,
this.height / 3 * 2,
this.width / 2,
this.height / 2
);
ctx.bezierCurveTo(
this.width / 2,
this.height / 3,
this.width / 3 * 2,
0,
this.width / 4 * 3,
0
);
ctx.lineTo(0, 0);
ctx.fill();
}
}
registerPaint("button", Button);
复制代码
See the Pen Button-Worklets by Shaw Che (@sche) on CodePen.
注册这个PaintWorklet
第二步,在页面中注册这个PaintWorklet。
if (!CSS.paintWorklet) {
document.querySelector('#alert').classList.add('show-alert');
} else {
CSS.paintWorklet.addModule("https://codepen.io/sche/pen/KRadBG.js");
}
复制代码
<div id="alert" class="alert">
You need support for CSS Paint API to view this demo. Go to here to find a good web browser.
<a href="https://ishoudinireadyyet.com/">ishoudinireadyyet.com</a>
</div>
<input type="button" class="my-button" value="btn">
</input>
<input type="button" class="my-button" value="btn 2"></input>
<span class="my-button">
span btn
</span>
复制代码
.my-button {
--my-bg-color: lightblue;
width: 70px;
height: 20px;
border-radius: 10px;
color: black;
background-image: paint(button);
}
.alert {
display: none;
}
.show-alert {
display: block !important;
}
复制代码
See the Pen Houdini - Button by Shaw Che (@sche) on CodePen.
Reference
- https://drafts.css-houdini.org/
- https://ishoudinireadyyet.com/
- https://www.smashingmagazine.com/2016/03/houdini-maybe-the-most-exciting-development-in-css-youve-never-heard-of/
- https://zhuanlan.zhihu.com/p/35479957
- 封面图片 - Photo by Denise Johnson on Unsplash