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()函数调用了名为awesomePatternworklet,但它还不会起任何的作用。但不急,接着往下看。

第二步: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回调中,我们有ctxgeomproperties三个参数。ctx<canvas>元素中获得的2D上下文相同(好的,差不多:<canvas>元素允许读取像素数据,而CSS Paint API则不能)。它允许我们使用所有相同的方法来绘制,就像我们在<canvas>上绘制一样。在上面的例子中,我只是用arc()函数绘制了一个圆。

arc()函数的前两个值是圆位置的XY坐标,其在元素的左上角。但是,我希望这个圆在正中间,这就是geom的用处所在。它实际上传递的是PaintSize,也就是图像通常填充区域的大小,我们可以访问widthheight信息,这也正是我们所需要的,使圆形位于正中心:

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-sizebackground-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会变得更棒!

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/css/the-css-paint-api.htmlNike Kyrie 5 EP 'UFO'