CSS Paint API

Chrome 65 的新机遇

CSS Paint API(也称为“CSS Custom Paint”或“Houdini’s Paint worklet”) 从 Chrome 65 开始默认处于启用状态。Google 优惠是什么?可以采取的措施 该怎么办?它的工作原理是什么?请继续阅读,你会不会...

借助 CSS Paint API,您可以通过编程方式, 属性需要图片。媒体资源(例如 background-imageborder-image) 通常与 url() 结合使用,用于加载图片文件或与内置的 CSS 结合使用 函数,如 linear-gradient()。您不用再使用这些变量 paint(myPainter),用于引用绘制 Worklet

编写 Paint Worklet

如需定义名为 myPainter 的绘制 Worklet,我们需要加载 CSS 绘制 使用 CSS.paintWorklet.addModule('my-paint-worklet.js') 创建 Worklet 文件。在该部分中, 因此可以使用 registerPaint 函数注册绘制 worklet 类:

class MyPainter {
  paint(ctx, geometry, properties) {
    // ...
  }
}

registerPaint('myPainter', MyPainter);

paint() 回调内,我们可以使用 ctx,就像使用 与 <canvas> 中的 CanvasRenderingContext2D 相同。如果您知道如何 在 <canvas> 中绘制后,您可以在 Paint Worklet 中绘制!geometry 告诉我们 画布的宽度和高度。properties我会 我们将进一步讨论此问题

作为一个入门示例,我们编写一个棋盘格颜料 Worklet 并使用它 用作 <textarea> 的背景图片。(我使用文本区域是 可默认调整大小):

<!-- index.html -->
<!doctype html>
<style>
  textarea {
    background-image: paint(checkerboard);
  }
</style>
<textarea></textarea>
<script>
  CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
  paint(ctx, geom, properties) {
    // Use `ctx` as if it was a normal canvas
    const colors = ['red', 'green', 'blue'];
    const size = 32;
    for(let y = 0; y < geom.height/size; y++) {
      for(let x = 0; x < geom.width/size; x++) {
        const color = colors[(x + y) % colors.length];
        ctx.beginPath();
        ctx.fillStyle = color;
        ctx.rect(x * size, y * size, size, size);
        ctx.fill();
      }
    }
  }
}

// Register our class under a specific name
registerPaint('checkerboard', CheckerboardPainter);

如果您以前使用过 <canvas>,应该不会对此代码感到熟悉。请参阅 直播 演示 此处。

以棋盘图案作为背景图片的文本区域
采用棋盘图案作为背景图片的文本区域。

与此处使用普通背景图片的不同之处在于: 每当用户调整文本区域的大小时,都会按需重新绘制。这意味着 背景图片的大小始终完全符合要求,包括 为高密度显示屏提供补偿。

这很酷,但同时也是静止的。我们要不能编写新的 每次我们想要相同的图案,但大小不同 正方形?答案是否定的!

将 Worklet 参数化

幸运的是,Paint Worklet 可以访问其他 CSS 属性, 这个额外的参数 properties 就派上用场了。为该类指定 static inputProperties 属性,您可以订阅任何 CSS 属性的变化, 包括自定义属性这些值将通过 properties 参数。

<!-- index.html -->
<!doctype html>
<style>
  textarea {
    /* The paint worklet subscribes to changes of these custom properties. */
    --checkerboard-spacing: 10;
    --checkerboard-size: 32;
    background-image: paint(checkerboard);
  }
</style>
<textarea></textarea>
<script>
  CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
  // inputProperties returns a list of CSS properties that this paint function gets access to
  static get inputProperties() { return ['--checkerboard-spacing', '--checkerboard-size']; }

  paint(ctx, geom, properties) {
    // Paint worklet uses CSS Typed OM to model the input values.
    // As of now, they are mostly wrappers around strings,
    // but will be augmented to hold more accessible data over time.
    const size = parseInt(properties.get('--checkerboard-size').toString());
    const spacing = parseInt(properties.get('--checkerboard-spacing').toString());
    const colors = ['red', 'green', 'blue'];
    for(let y = 0; y < geom.height/size; y++) {
      for(let x = 0; x < geom.width/size; x++) {
        ctx.fillStyle = colors[(x + y) % colors.length];
        ctx.beginPath();
        ctx.rect(x*(size + spacing), y*(size + spacing), size, size);
        ctx.fill();
      }
    }
  }
}

registerPaint('checkerboard', CheckerboardPainter);

现在,我们可以使用相同的代码绘制所有不同类型的棋盘。但 现在,我们可以进入开发者工具,摆弄这些值 直到找到合适的外观。

不支持绘制 Worklet 的浏览器

在撰写本文时,只有 Chrome 实现了绘制 Worklet。时间 是来自所有其他浏览器供应商的积极信号,因此进展不大。 如需随时掌握最新动态,请参阅 Is Houdini Ready Yet? 。在此期间,请务必使用渐进式 一些增强功能,即使在不支持绘制时也能确保代码正常运行 Worklet。为了确保一切按预期运行,您必须 CSS 和 JS。

您可以通过检查 CSS 对象来检测 JS 中对绘制 worklet 的支持: js if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('mystuff.js'); } 在 CSS 方面,您有两种选择。您可以使用 @supports

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

一个比较巧妙的技巧是,CSS 会让内容失效,随后 如果其中包含未知函数,则忽略整个属性声明。如果 您需要指定两次属性,第一次不使用 Paint Worklet,然后使用 绘制 Worklet - 您将获得渐进式增强:

textarea {
  background-image: linear-gradient(0, red, blue);
  background-image: paint(myGradient, red, blue);
}

在支持绘制 Worklet 的浏览器中,第二个声明是 background-image 将覆盖第一个。在不支持的浏览器中 对于 Paint Worklet,第二个声明无效,将被舍弃, 第一个声明才开始生效。

CSS 绘制 Polyfill

有多种用途,也可以使用 CSS 绘制 Polyfill、 它为现代浏览器添加了 CSS Custom Paint 和 Paint Worklets 支持。

使用场景

Paint Worklet 有很多用途,其中一些比 其他。其中比较显而易见的方法之一是使用 Paint Worklet 来缩减大小 DOM 的一部分。通常,添加元素纯粹是为了打造装饰 使用 CSS 文件例如,在 Material Design Lite 中,按钮 包含 2 个额外的 <span> 元素,用于实现 涟漪本身。如果您有很多按钮,那么这些按钮加起来可能会比较多 并可能导致移动性能下降。如果您 使用绘制 Worklet 实现涟漪效果 最终将得到 0 个其他元素,而只有一个 Paint Worklet。 此外,您还可以更轻松地自定义 参数化。

使用 Paint Worklet 的另一个优点是,在大多数情况下 就字节而言,使用绘制 worklet 很小。当然,还有 权衡:当画布尺寸或任意尺寸发生变化时,绘制代码就会运行 更改。因此,如果您的代码复杂且耗时较长, 卡顿。Chrome 正在努力将绘制 Worklet 移出主线程, 就算是长时间运行的 Paint Worklet,也不会影响主要 Paint Worklet 线程。

对我来说,最激动人心的前景是 Paint Worklet 能够实现高效的 对 CSS 功能进行 polyfill 操作。例如, 对圆锥梯度执行 polyfill 操作, 就会以原生方式登录 Chrome再比如,在一次 CSS 会议中, 决定现在可以有多种边框颜色这场会议的进行期间 工作之余,我的同事 Ian Kilpatrick 为这个新的 CSS 编写了一个 polyfill 绘制 Worklet 的行为。

跳出思维定式

大多数人在看到背景图片或边框图片时 Paint Worklet。Paint Worklet 有一个不太直观的用例, mask-image,可使 DOM 元素具有任意形状。例如, diamond

<ph type="x-smartling-placeholder">
</ph> 一个菱形的 DOM 元素。 <ph type="x-smartling-placeholder">
</ph> 一个菱形的 DOM 元素。

mask-image 接受与元素大小相同的图片。哪些区域 表示图片是透明的,则该元素是透明的。戴口罩的区域 image 为 opaque,则元素不透明。

现已在 Chrome 中推出

Paint worklet 已在 Chrome Canary 版中推出一段时间。对于 Chrome 65, 默认处于启用状态开始尝试新的可能性 这个绘制 worklet 就会打开,让我们看看你构建了什么!如需更多灵感 查看 Vincent De Oliveira 的作品