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,其中包含更多详细信息。 数字表示浏览器在该版本及更高版本中支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
65 | 否 | 否 | 79 | 否 |
移动设备/平板电脑
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 否 | 127 | 否 |
但是,还有很长的路要走。
无论如何,让我们来看看如何创建代码来使用它。 我将把它分解为三个阶段。 我们将在过程中使用一些新的 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
回调中,我们有 ctx
、geom
和 properties
。 ctx
与我们从 <canvas>
元素中获得的 2D 上下文相同。(实际上,几乎相同:<canvas>
元素允许读取像素数据,而使用 CSS Paint API 则不能。)它允许我们像在画布上一样使用所有相同的方法来绘制。 在上面的示例中,我只是使用 arc
函数绘制一个圆圈。
arc
函数的前两个值是圆圈在元素左上角的 X 和 Y 坐标(以像素为单位)。 但是,我希望圆圈位于中心,这就是 geom
数据派上用场的地方。 它实际上返回的是 PaintSize
,即图像通常填充的区域的大小,我们可以访问 width
和 height
信息,这正是我使圆圈位于中心所需要的。
查看 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-size
和 background-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 即将变得更加强大!
这在未来可能会有用。就目前而言,我看到了一种使用内联 SVG 和 SCSS 来实现基本相同效果的方法。
我不会重复 Chris 关于使内联 SVG URL 正常工作的信息,但可以肯定地说,有一种方法可以在所有支持 SVG 的现代浏览器中正常工作。
Chris 方法的一个主要缺点是 SVG 必须经过 URL 编码。这使得编辑变得很困难。因此,我开始寻找解决方案,并找到了这个笔,它使用 SCSS 从字符串进行 URL 编码。这意味着你也可以像在上面使用 CSS 变量那样使用 SCSS 变量。只需将它们嵌入到 SVG 字符串中,使用
#{$var}
。“那么,我现在可以使用它吗?可以!CSS Paint API 仅在 Chrome 65 中受支持。”
这是一个有趣的“使用”定义。:-) CanIUse.com 会说不行。
我会说我们现在可以尝试使用它,但绝对不能使用它,除非你希望有一半的观众无法看到它。
嗨,Tim!
是的,我想“你可以”这个短语有点强硬。但是你可以简单地使用
background-image: url('fallback.jpg');
作为简单的回退,这样你的用户至少不会看到空白!:)很棒的文章!喜欢体验 Houdini 为我们准备的所有美味佳肴。
谢谢,Tim!是的,我也是 :) 看到事情的发展方向真是令人兴奋!
可能值得注意的是,有一个适用于所有现代浏览器的 CSS Paint 填充程序。
https://github.com/GoogleChromeLabs/css-paint-polyfill