CSS paint 实现Material Design Button

效果:

CSS PAINT API

CSS Paint API,是API集合Houdini中的一部分,可以用来绘制图像,并作为需要设置image的css属性的值,比如background-image,border-image。

其他API如Layout API来实现布局,Parser API解析CSS表达式等。不过整体来说Houdini目前的浏览器支持性还不是很好。

使用Paint API:
首先在css中用paint(paintWorkletName)来引用需要的paint worklet

.selector {
  background-image: paint(ripple);
}

使用CSS.paintWorklet.addModule添加paint worklet文件

CSS.paintWorklet.addModule('paint.js');

js文件中使用reginsterPaint注册一个paint worklet类

// paint.js
class Painter {
  static get inputProperties () {
   // return [...];
  }

  paint(ctx, geom, properties) {
    // ...
  }
}
registerPaint('ripple', Painter);

类中paint函数参数:
ctx 渲染上下文,是CanvasRenderingContext2D的子集,熟悉canvas的话使用着和它差不多。上面例子中绘制了一个圆形

ctx.fillStyle = color;
ctx.globalAlpha = 1 - tick / 400; // 动画时间设置为400,透明度逐渐降低为0
ctx.arc(
  x, y, // 圆弧的圆心位置x,y
  geom.width * tick / 400, // 半径逐渐变大
  0, // 开始弧度 
  2 * Math.PI // 结束弧度
);

geom 返回PaintSize,geom.width和geom.height表示绘制图像的宽高

properties 获取元素的计算样式,是inputProperties中返回的部分,例如绘制圆形需要颜色,坐标,半径(半径根据时间推进增加,使用的tick传递的当前时间和开始时间的差值),可以这样写:

static get inputProperties () {
  return ['--x', '--y', '--tick'];
}

然后通过parit函数的第三个参数获得这些css变量:

const color = properties.get('--color').toString();
const x = properties.get('--x').toString();
const y = properties.get('--y').toString();
let tick = properties.get('--tick').toString();

当css变量发生变化的时候,也会触发paint函数执行,更新绘制的图像。
点击按钮后使用requestAnimationFrame让--tick连续变化,绘制了一个从小到大变化的圆。

关于Paint API需要注意的是:

  • Paint API需要在https上运行,本地localhost也可以
  • Paint Wroklet中不能访问DOM

浏览器兼容

浏览器支持(from caniuse.com)

在js中判断浏览器是否支持

if ('paintWorklet' in CSS) {
   CSS.paintWorklet.addModule('xxx.js');
}

CSS中可以使用feature queries

@supports (background: paint(id)) {
  /* ... */
}

如果不支持,可以做降级处理,用其他图片代替,或者也可以

div {
  background-image: linear-gradient(to bottom, red, green);
  background-image: paint(paintWorklet);
}

支持的浏览器会使用paint,不支持的则会忽略它而使用渐变。

参考:
CSS Houdini: Ripple animation - @iamvdo

The CSS Paint API | CSS-Tricks
CSS Paint API | Google Developers

Comments
Write a Comment