CSS Paint API 初体验

一、技术背景:

你是否在项目开发时想使用一些特别的CSS样式,却因为未曾得到所有浏览器的支持而选择放弃?如果这些事情都曾困扰过你,那你可以关注一下CSS Houdini。

CSS Houdini 是由一群来自 Mozilla, Apple, Opera, Microsoft, HP, Intel, IBM, Adobe 与 Google 的工程师所组成的工作小组,志在建立一系列的 API,让开发者可以自定义扩展CSS,并把这些样式放入浏览器的渲染引擎直接渲染出来,用来解決 CSS 长久以来的问題:

跨域问题

CSS Polyfill 的制作困难

我们知道一般浏览器渲染主要流程是:

HTML解析将HTML标记解析成 DOM Tree

CSS解析将CSS解析成CSSOM(CSS Object Model)

将二者关联生成Render Tree

应用正确的层叠顺序应用规则

布局(Layout):通过Render Tree中渲染对象的信息,计算出每一个渲染对象的位置和尺寸

根据计算好的信息Painting制整个页面

下图展示为:现有JavaScript访问浏览器渲染管道 与 Houdini试图提供API后的访问对比图

CSS Typed OMCSSOM 的强化版,最主要的功能在于将 CSSOM 所使用的字串值转换成具有型別意义的 JavaScript 表示形态

CSS Layout API允许开发者自定义布局模块。这将会为开发者带来性能媲美原生布局的方式,比如display: flex和display: grid

CSS Paint API下文需要介绍的API,允许开发者通过Paint API 画出图像,然后把这些图像运用到合适的CSS属性上,比如 background-image、border-image、list-style-image 和 cursor 等属性上。

二、CSS Paint 使用方式:

1、 定义 Paint Worklet,用registerPaint()

2、 在 CSS 中使用指定的 Paint Worklet,用paint()

3、 加载定义了 Paint Worklet 的脚本文件,用CSS.paintWorklet.addModule()

三、方法解析:

CSS.paintWorklet.addModule()

CSS 的 paintWorklet 属性中提供了与绘制相关的 Worklet,该Worklet类似于Web worker,它们允许您导入脚本文件并运行JavaScript代码,(1)可以在渲染管道中的各个点调用,(2)独立于主线程。

CSS.paintWorklet.addModule('xxx.js') 用来加载已定义好的CSS Paint Worklet

registerPaint()

paintWorklet的PaintWorkletGlobalScope只给开发人员暴露了一个方法registerPaint(),用来注册。

registerPaint(name, paintCtor) 有两个参数:

name 是 Paint Worklet 的名字。必填,且唯一

paintCtor 是一个Class类。

paint()

在paintCtor的类里有个函数paint(),它是渲染引擎在浏览器绘制阶段的回调。

回调会传3个参数 paint(ctx, size, properties):

ctx 是一个PaintRenderingContext2D对象

size 绘制的图像大小,它有两个只读属性 width 和 height

properties 是一个StylePropertyMapReadOnl

y对象,它只包含inputProperties里列出的属性

以下三种情况,都会触发回调的调用:

视口要显示绘制的元素了。 eg:初始创建 Paint 类的实例对象时

绘制区域的大小变了 eg:网页响应式变化

inputProperties 列出的属性值变 eg:图像可根据参数的改变而改变

其中,PaintRenderingContext2D 是 CanvasRende

ringContext2D 的子集。所以会用 Canvas 的小伙伴也就会在 Paint Worklet 里绘制图像了。它目前不支持 CanvasImageData, CanvasUserInterface, Canv

asText, CanvasTextDrawingStylesAPIPaintRender

ingContext2D 对象有一个输出位图,当类的实例被创建时,它就被初始化。输出位图的大小是它呈现的对象的具体大小,因为实际输出的图像会根据设备像素比的不同而不同。浏览器会记住paint()里绘制的操作序列,以便动态适应不同的设备像素比,这样就保证了图像在高清屏下的显示质量。

inputProperties()

可以在paint()回调里访问它们,这些属性会通过第三个参数properties传过去

Paint Worklet 会订阅这些属性,以便在它们的值发生改变时触发paint()回调,以实时重新绘制图像

CSS Paint()

参数 circle 就是 Paint Worklet 的名字,即在registerPaint(name, paintCtor)里提供的 name。

paint()是 CSS 的 类型支持的一种写法。我们平时用url()加载图片或者用渐变函数linear-gradient()的地方都可以使用paint()。它可以用在 background-image、border-image、list-style-image 和 cursor 等属性上。

并不是在 CSS 里每调用一次piant()就执行一次 Paint Worklet 类的 paint 方法,而是当元素的大小改变时,或者 inputProperties 里声明的属性值改变时才会触发

四、实例解析

波浪纹状态图

在本实例中使用正弦函数来实现波浪纹效果。

使用公式:y = A sin(Bx + C) + D

振幅A:控制波浪的高度

周期B: 控制波浪的宽度

相移C: 控制波浪的水平移动

垂直位移D: 控制水位的高度

y = 波浪高度 * sin(x *波浪宽度 + 水平位移)

2、代码

首先定义好波浪纹需要的自定义变量

再定义 wave-box Paint Wortket

加载已定义好的CSS Paint Worklet

因为CSS Paint Worklet 并不能直接操作setInterval,所以我们在外部通过不断改变水平偏移(xOffset)自定义变量,让波浪纹动起来

3、预览地址:

https://codepen.io/caifeng/pen/bQdrpq

小提示:CSS Houdini只能工作在localhost域名或者是https的环境,否则的话相关API是不可见的(undefined)。所以如果你是在本地开发,可以用 http-server 在本地快速搭建一个服务器

多边形切换

上个波浪纹例子其动画的实现是通过外部JS不断改变自定义变量来实现Paint绘制,当然也可以直接在CSS文件中直接操作改变自定义变量来实现Paint绘制。

CSS Paint其定义,引用和上个例子类似,本例就不重复了。在本例子通过 animation 来改变自定义变量“--number”来控制显示的多边形的边数

CSS Paint 绘制的图片 与 传统的background-image 的差别就是background-image 是根据代码计算出来,不会随着元素的大小变化而伸缩而CSS Paint绘制的图像总是会和元素容器所需保持一样大。意味着你修改元素大小可视区域时,CSS Paint 都会重新绘制。

预览地址:

https://codepen.io/caifeng/pen/pQKVPL

雪花效果

因为CSS Paint 展现很大程度和Canvas类似,在本例中小编主要是看其与原生的Canvas实现同样效果有什么区别,借助Chrome浏览器的Performance工具可以看到:

Css Paint的绿色竖线更高,FPS 更高

Css Paint的CPU 资源占用率更低

小提示:在本实例中需要通过随机数来生成雪花,但是在实际的操作过程中,发现一个问题,它会初始化两次snow.js,在paint的时候也会随机切换,如下图所示

具体原因未知,新技术的出现可能总有一些未知问题,可这样造成有两个随机雪花点的的数据,为绕过这一问题,参考资料利用随机种子来生成随机数,使每次Paint生成的随机数组一样

预览地址:

https://codepen.io/caifeng/pen/wQyWWd

五、浏览器支持情况

截止目前,CSS Painting API 的浏览器支持情况如下:

Chrome 65+ 和 Opera 52+ 已经支持

Firefox 有实现的意愿

Safari 还在考虑

Edge 暂无反馈

不支持的浏览器优雅降级方案

在写 CSS 时,使用@supports或给属性写个备用值

在 JS 里加载 Paint Worklet 之前,先做个判断

六、优缺点:

实现动画不需要新增 DOM 节点

在浏览器渲染管道中执行,效率高。

Houdini 的实现之路漫漫。

虽然它可以缓解兼容问题,但首先,浏览器们得先兼容 Houdini…

浏览器需加载 Paint Worklet

Paint Worklet无法操作 DOM 和全局方法(比如 setInterval,setTimeout等)

七、结语:

CSS Painting API 让我们绘制图片又多了一种可能,在CSS Houdini上有不少有意思DEMO,或许在这些例子中,你会产生一些新的灵感。

八、参考文章

1、https://css-tricks.com/the-css-paint-api/

2、https://css-houdini.rocks/

3、https://drafts.css-houdini.org/css-paint-api/

4、https://juejin.im/post/5b4ffa045188251b134e7

211

5、https://www.smashingmagazine.com/2016/03/

houdini-maybe-the-most-exciting-development-in-css-youve-never-heard-of/

6、https://www.desmos.com/calculator/hqbavmm

w5p

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181130G085LT00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券