CSS Paint API
特别声明,本文根据@RUTH JOHN的《The CSS Paint API》一文所整理。
CSS Paint API是一个令人非常兴奋的东西,也是令人激动人心的时刻,它将开启CSS新的旅程。接下来让我们一起来看看它是什么,为什么会有它以及如何开始使用它。
CSS Paint API是什么
CSS Paint API只是CSS Houdini所有规范中的一部分。实际上,CSS 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(稍后我们将介绍它是如何工作的)。
酷而复杂
太好了!使用常规图片绝对没有什么错,而且我们一直都是这么做的。仅仅因为某样东西是新的并且可能很酷,这并不意味着我们所有人都必须开始把它用于项目上。然而,图像是静态的,但生成动态的东西想法是诱人的!
我们都知道,CSS的性线渐变(linear-gradient
)是非常强大的。看看这些你就会认同我所说的。但是,你能想象在没有多幅背景图像的情况下,创建这些分层模式的工作量会减少多少吗?不仅如此,深入到CSS Paint API中还可以帮助你理解在运行时如何生成这些图像,这是非常有用的(这也是我们将要做的)。
那么浏览器还不支持的conic-gradient
又如何呢?也就是说,在没有任何Polyfill的情况之下,利用CSS Paint API可以创建一个conic-gradient
和一些属性,使其与实际的规范完全相同。所以,实际上你是在创造原生的Polyfill。这非常的棒!
记住,这是CSS Houdini的更大的一部分。以下是来自Wiki对CSS Houdini的描述:
CSS-TAG Houdini工作组(CSS Houdini)的目标是共同开发一些功能来增强Web上样式和布局的“魔力”!
听起来不错,对吧!正是如此,这些新特性旨在允许Web开发人员扩展CSS本身的特性,提供更好的控制、跨浏览器的支持和原生的Polyfill。
标准过程可能需要一段时间:从提出一个新的CSS特性,到编写一个规范,再到让浏览器供应商实现这个新规范(这个过程大家都知道)。由于开发人员常常渴望尽快开始使用一个新特性,我们必须考虑到浏览器老版本可能不支持。如果它尚未完全实现,更不用说典型的细微差别的跨浏览器实现。CSS Houdini可以允许我们自己实现跨浏览器的支持,而我们只需要等待浏览器供应端赶上来,但这并不会影响我们CSS新特性的使用,哪怕是未进入规范的新特性(前提是浏览器对CSS Houdini有全面的支持)。
@Philip Walton在Smashing Magazine的文章中很好的解释了CSS Houdini的这些好处。你也可以看看@Ana Tudor是如何使用CSS Houdini来创建复杂的动画的。
现在可以用吗
你现在就可以用! CSS Paint API在Chrome 65中已得到支持。你也可以持续关注caniuse.com,这里有一个支持图表,随着时间的推移会不断更新。
哪一天表格是都是绿色的时候,代表你完全可以使用CSS Paint API。
不管怎样,让我们看看如何使用它。接下来我把它的使用分成三个阶段。我们将在此过程中使用一些新的JavaScript特性。代码已经为你准备好了,但我们还是将会逐一介绍。
第一步:CSS部分
首先,我们需要在CSS中调用自己命名好的worklet
。比如有这里,这个worklet
命名为awesomePattern
,所以在CSS可以像下面这样使用:
section {
background-image: url('fallback.png');
background-image: paint(awesomePattern);
}
虽然我们在CSS中通过paint()
函数调用了名为awesomePattern
的worklet
,但它还不会起任何的作用。但不急,接着往下看。
第二步: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则不能)。它允许我们使用所有相同的方法来绘制,就像我们在<canvas>
上绘制一样。在上面的例子中,我只是用arc()
函数绘制了一个圆。
arc()
函数的前两个值是圆位置的X
和Y
坐标,其在元素的左上角。但是,我希望这个圆在正中间,这就是geom
的用处所在。它实际上传递的是PaintSize
,也就是图像通常填充区域的大小,我们可以访问width
和height
信息,这也正是我们所需要的,使圆形位于正中心:
class Shape {
paint(ctx, geom, properties) {
let x = geom.width/2;
let y = geom.height/2;
ctx.strokeStyle = 'white';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(x, y, 50, 0, 2*Math.PI);
ctx.stroke();
ctx.closePath();
}
}
效果如下:
很好,但这是一个非常简单的示例。你可以换圆圈换成更棒的,比如下面这个示例:
上面这个示例,给类添加了一个叫做drawStar
的方法,这个方法中有一大堆的canvas
函数,用来绘制CSS-Tricks网站的Logo图标。
第三步:自定义属性
事实上,我们可以做更多的事情!可以复用CSS自定义属性的强大特性。我们都为此感到兴奋的原因之一,就是CSS自定义属性。
假设我们想要改变CSS-Tricks的Logo图标的大小或颜色。我们可以把这些参数作为自定义属性放到CSS中,然后用回调函数中的第三个参数来访问它们。
在CSS中添加一个--star-scale
属性,它最终可以用来缩放Logo。另外一个是--star-color
属性,可以很容易的改变Logo的颜色。
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
或--star-color
属性的值,这样就可以更新Logo的大小和颜色。
同样需要注意的是,所有常见的CSS的
background
属性都可以正常的工作,比如background-size
和background-repeat
。这真的太棒了,而且仍然非常有用!
总结
这是非常强大的东西,不仅仅是定制的背景图片。想象在你的元素上有一个半边或双边。你通常可以使用::before
或::after
伪元素,或者可能使用经过精心设计的box-shadow
。你可以用CSS Paint API和border-image
属性来实现它。
这个API真正的汇集了许多很酷的特性,比如worklets、ECMAScript2015的类和canvas
。此外,它还提供了整个JavaScript交互层。你可以很容易地添加事件来更新自定义属性,从而更新图像本身,例如这个来自@Surma写的案例。这个Demo利用click
事件来更新requestAnimationFrame
函数中的属性,以便在用户每次点击button
时创建动画。它甚至可以考虑点击的坐标。
这看起来似乎有点复杂,但让我们看看Houdini的其他部分,我们即将遇到:
- CSS Layout API,它允许我们做一些类似
display:Layout("myCustomLayout")
的事情,对于这个API,典型的示例就是定制瀑布流布局,但范围要大得多 - **CSS Properties and Values API**允许我们为自定义属性指定类型
- CSS Animation Worklet API,它从主线程中获取和处理动画,这样一来就可以创建流畅的动画效果
所以,不管你是否真的对这个特殊的新功能感兴趣,它都是一大堆新技术的一部分,将释放出大量的能量。这意这个空间,因为CSS会变得更棒!
如需转载,烦请注明出处:https://www.fedev.cn/css/the-css-paint-api.htmlNike Kyrie 5 EP 'UFO'