CSS Paint API

Avatar of Ruth John
Ruth John

DigitalOcean 提供适合您旅程各个阶段的云产品。 立即开始使用 200 美元的免费积分!

CSS Paint API 非常令人兴奋,不仅因为它本身,还因为它代表着 CSS 发展的一个激动人心的开始。 让我们来了解一下它是什么、为什么有它以及如何开始使用它。

什么是 CSS Paint API?

该 API 只是被称为 CSS Houdini 的一系列新规范的一部分。 本质上,Houdini 使开发人员能够 更低级别地访问 CSS 本身。 不开玩笑。

CSS Paint API 特别允许您在通常写入图像预期值的任何位置调用 paint() 函数。 一个常见的例子是 background-image 属性,您可以在其中使用 url() 函数链接到图像文件,如下所示

area {
  background-image: url('assets/myimage.jpg');
}

CSS Paint API 允许您 代替 调用 paint() 函数,并传入一个您已通过 JavaScript 定义的 paint worklet。 可以将其视为允许您以编程方式绘制(几乎)任何内容的一段代码。 而且因为它是 JavaScript,您也可以使其动态化。 该 API 本身与 HTML5 的 <canvas> API 非常相似(我们将在稍后了解它的工作原理)。

这听起来很酷,但也很复杂。 我已经很满意使用常规图像了…

太好了! 使用您一直在使用的常规图像绝对 没有 错。 仅仅因为某件事是新事物并且可能很酷,并不意味着我们都必须开始将它用于所有事情。 然而,图像是静态的,动态生成东西的想法很诱人!

让我们考虑一下 linear-gradient 一分钟。 它非常强大。 我的意思是,看看这些。 但是,你能想象如果 没有 多个背景图像,创建这些分层图案会减少多少工作量吗? 不仅如此,深入研究 CSS Paint API 还将帮助您了解这些类型的图像在运行时是如何生成的,这可能非常有用(也是我们即将做的事情)。

关于 conic-gradient 目前还没有浏览器支持 (现在 有一些支持,但这一点仍然成立) … 也就是说,没有 polyfill。 利用 Paint API 允许您创建圆锥渐变和一些属性来更改它,与实际规范相同。 所以,实际上,您实际上是在创建您自己的原生 polyfill。 那真是太棒了!

请记住,这都是更大 CSS Houdini 功能组的一部分。 以下摘自 CSS Houdini Wiki

CSS-TAG Houdini 任务组 (CSS Houdini) 的目标是共同开发解释网络上样式和布局“魔力”的功能。

听起来不错,对吧? 的确如此,这些新功能旨在允许开发人员扩展 CSS 本身的功能,提供更好的控制、跨浏览器支持和 polyfill。

标准过程可能需要一段时间:从提出新的 CSS 功能到编写规范,再到浏览器供应商实施此新规范。 由于开发人员通常渴望尽快开始使用新功能,因此我们必须考虑旧版浏览器可能不支持该功能 以及 规范可能发生的任何更改,如果它尚未完全实施——更不用说跨浏览器实施的典型细微差别了。 Houdini 可以帮助我们解决这个问题,因为它允许我们在等待供应商赶上来的时候自己实施浏览器功能。

Philip Walton 在 Smashing Magazine 上的这篇精彩文章中 对 Houdini 的这些好处进行了很好的解释。

您可以看到 Ana Tudor 如何 已经将它用于 创建复杂的动画。

那么,我现在可以使用它吗?

可以! 在撰写本文时,CSS Paint API 仅在 Chrome 65 中受支持,但以下是一个支持图表,它将随着时间的推移而保持更新

此浏览器支持数据来自 Caniuse,其中包含更多详细信息。 数字表示浏览器在该版本及更高版本中支持该功能。

桌面

ChromeFirefoxIEEdgeSafari
6579

移动设备/平板电脑

Android ChromeAndroid FirefoxAndroidiOS Safari
127127

但是,还有很长的路要走。

无论如何,让我们来看看如何创建代码来使用它。 我将把它分解为三个阶段。 我们将在过程中使用一些新的 JavaScript 功能,但代码就在那里,我们将逐一讲解。

步骤 1:CSS

首先,我们需要为我们的 worklet 命名并在 CSS 中调用它。 我将把它命名为 awesomePattern,所以我的 CSS 会像这样

section {
  background-image: url('fallback.png');
  background-image: paint(awesomePattern);
};

我们已经设置好了,但现在还不会发生任何事情。

步骤 2:JavaScript

现在,我们需要将我们的 paint worklet 添加到我们的主 JavaScript 中,它正在加载另一个 JavaScript 文件,如下所示

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

尽管如此,此时仍然不会发生任何事情,因为它位于我们的 patternWorklet.js 文件中,所有工作将在那里完成。

patternWorklet.js 中,我们需要注册一个 paint worklet 类

registerPaint('awesomePattern', Shape);

因此,我们调用 registerPaint() 函数并传入我们想要调用的 paint worklet 的名称(在本例中为 awesomePattern),以及对我们即将编写的类的引用(在本例中为 Shape)。 请记住在定义我们即将定义的类 之后 添加此项。 与 JavaScript 中的函数提升不同,您 确实 需要在使用类之前定义类。

接下来,我们将使用 ECMAScript2015 类语法来编写一个类,该类将为我们绘制背景。 因为它现在已注册为 paint worklet 类,所以我们免费获得了一些东西。

class Shape {
  paint(ctx, geom, properties) {

    ctx.strokeStyle = 'white';
    ctx.lineWidth = 4;
    ctx.beginPath();
    ctx.arc( 200, 200, 50, 0, 2*Math.PI);
    ctx.stroke();
    ctx.closePath();

  }
}

paint 回调中,我们有 ctxgeompropertiesctx 与我们从 <canvas> 元素中获得的 2D 上下文相同。(实际上,几乎相同:<canvas> 元素允许读取像素数据,而使用 CSS Paint API 则不能。)它允许我们像在画布上一样使用所有相同的方法来绘制。 在上面的示例中,我只是使用 arc 函数绘制一个圆圈。

arc 函数的前两个值是圆圈在元素左上角的 X 和 Y 坐标(以像素为单位)。 但是,我希望圆圈位于中心,这就是 geom 数据派上用场的地方。 它实际上返回的是 PaintSize,即图像通常填充的区域的大小,我们可以访问 widthheight 信息,这正是我使圆圈位于中心所需要的。

查看 CodePen 上 Rumyra (@Rumyra) 的 简单圆圈:CSS Paint API 示例

很好,但这只是一个非常简单的示例。 让我们用更酷的东西替换圆圈

查看 CodePen 上 Rumyra (@Rumyra) 的 简单圆圈:CSS Paint API 示例

在这里,我在类中添加了一个名为 drawStar 的方法,并且那里正在进行大量的画布函数,这些函数绘制了 CSS-Tricks 徽标。”

第三步:自定义属性

我们可以做得更多!我们可以利用CSS 自定义属性(也称为变量)的力量。我们都对它们感到非常兴奋,这也是原因之一。

假设我想改变 CSS-Tricks 标志的大小或颜色?我们可以将这些参数作为自定义属性放入我们的 CSS 中,并使用回调数据的第三部分 properties 访问它们。

让我们在 CSS 中添加一个 --star-scale 属性,它最终会使我们的徽标变大或变小,以及一个 --star-color 属性,以便直接在 CSS 中轻松更改徽标的颜色。

section {
  --star-scale: 2;
  --star-color: hsla(200, 50%, 50%, 1);
  background-image: paint(awesomePattern)
};

回到我们的 paint worklet 类中,我们需要访问这些自定义属性。我们可以使用 inputProperties 方法来做到这一点,该方法使我们能够访问所有 CSS 属性及其给定的值。

static get inputProperties() { return ['--star-scale','--star-color']; }

现在,我们可以在 paint 方法中访问它们。

const size = parseInt(properties.get('--shape-size').toString());

…并在我们的代码中使用该值。因此,如果我们在 CSS 中更改 --star-scale--start-color 属性,它将更新背景!

值得注意的是,所有常见的 CSS background 属性都按预期工作,例如 background-sizebackground-repeat。这非常有用!

结论

这非常强大,不仅仅是用于自定义背景图像。想象一下,元素上有半边框或双边框。你通常会使用 ::before::after 伪元素,或者可能是精心设计的 box-shadow。你可以使用 CSS Paint API 和 border-image 属性来实现这一点(以及更多功能)。

这个 API 真正整合了许多很酷的功能,例如 worklets、ECMAScript2015 类和 canvas。此外,它还提供了 JavaScript 附带的整个交互层。你可以轻松地添加事件来更新自定义属性,从而更新图像本身,例如Surma 的这个示例,它利用点击事件在 requestAnimationFrame 函数中开始更新属性,以在用户每次点击按钮时创建一个动画。它甚至会考虑点击的坐标。

乍一看,这可能看起来有点复杂,但让我们看一下即将遇到的 Houdini 套件的其他部分。

  • CSS 布局 API,它应该允许我们做类似 display: layout('myCustomLayout') 的事情,其中典型的示例是自定义的砖石型布局,但范围要大得多。
  • CSS 属性和值 API,它允许我们为自定义属性指定类型。
  • CSS 动画 Worklet API,它从主线程获取动画处理,这将带来非常流畅的动画效果。

因此,无论你是否对这个特定的新功能感兴趣,它都是一堆新技术的组成部分,这些新技术将释放出巨大的力量。请关注此页面,因为 CSS 即将变得更加强大!