实战|使用CSS Paint API动态创建与分辨率无关的可变背景
source link: http://mp.weixin.qq.com/s?__biz=MzI0MDIwNTQ1Mg%3D%3D&%3Bmid=2676493995&%3Bidx=1&%3Bsn=c72a69b1f489771a45b1b482c4e0481a
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
来源:https://medium.com/better-programming,作者:Ferenc Almasi
现代Web应用对图像的需求量很大,它们占据网络下载的大部分字节。通过优化它们,你可以更好地利用它们的性能。如果你碰巧使用几何图形作为背景图像,有一个替代方案:你可以使用 CSS Paint API [1] 以编程方式生成背景。
在本教程中,我们将探讨其功能,并探讨如何使用它来动态创建与分辨率无关的动态背景。这将是本教程的输出:
参考阅读:CSS届的绘图板CSS Paint API简介,张鑫旭, https://www.zhangxinxu.com/wordpress/2018/11/css-paint-api-canvas/
目录:
-
设置项目
-
什么是worklet?
-
-
定义Worklet
-
绘制矩形
-
-
使背景动态化
-
在CSS中检查支持
-
访问绘画worklet中的参数
-
-
总结
设置项目
首先,创建一个新的 index.html
文件,并编写如下代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>:art: CSS Paint API</title> <link rel="stylesheet" href="styles.css" /> </head> <body> <textarea class="pattern"></textarea> <script> if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('pattern.js'); } </script> </body> </html>
有几件事要注意:
-
在第13行,我们加载了一个新的Paint worklet。目前,全球支持率约为63%。因此,我们必须首先检查是否支持
paintWorklet
。 -
我正在使用
textarea
进行演示,因此我们可以看到调整画布的大小将如何重绘图案。 -
最后,你需要创建一个
pattern.js
(用于注册绘画工作区)以及一个styles.css
,我们可以在其中定义几个样式。
什么是worklet?
Paint worklet是一个定义了应该画在画布上的内容的类。它们的工作原理与 canvas
元素类似。如果你以前有这方面的知识,代码会看起来很熟悉。然而,它们并不是100%相同的。例如,在worklet中还不支持文本渲染方法。
在这里,我们还要定义CSS样式。这是我们要使用worklet的地方:
.pattern { width: 250px; height: 250px; border: 1px solid #000; background-image: paint(pattern); }
我添加了一个黑色的边框,这样我们可以更好地看到 textarea
。要引用一个paint worklet,你需要把 paint(worklet-name)
作为一个值传递给 background-image
属性。但是 pattern
是从哪里来的呢?我们还没有定义它,所以让我们把它作为我们的下一步。
定义Worklet
打开 pattern.js
并添加以下内容:
class Pattern { paint(context, canvas, properties) { } } registerPaint('pattern', Pattern);
在这里可以使用 registerPaint
方法注册 paintWorklet
。你可以在此处定义的CSS中引用第一个参数。第二个参数是定义应在canvas上绘画的类。它具有一个包含三个参数的 paint
方法:
-
context PaintRenderingContext2D CanvasRenderingContext2D API
-
canvas
:这是我们的canvas,一个PaintSize
对象,只有两个属性:width和height。 -
properties
:这将返回一个StylePropertyMapReadOnly
对象,我们可以使用该对象通过JavaScript读取CSS属性及其值。
绘制矩形
下一步是显示一些东西,所以让我们绘制矩形。将以下内容添加到 paint
方法中:
paint(context, canvas, properties) { for (let x = 0; x < canvas.height / 20; x++) { for (let y = 0; y < canvas.width / 20; y++) { const bgColor = (x + y) % 2 === 0 ? '#FFF' : '#FFCC00'; context.shadowColor = '#212121'; context.shadowBlur = 10; context.shadowOffsetX = 10; context.shadowOffsetY = 1; context.beginPath(); context.fillStyle = bgColor; context.rect(x * 20, y * 20, 20, 20); context.fill(); } } }
我们在这里所做的就是创建一个嵌套循环,以循环遍历画布的宽度和高度。由于矩形的大小为20,因此我们要将矩形的高度和宽度除以20。
在第4行,我们可以使用模数运算符在两种颜色之间切换。我还为深度添加了一些阴影。最后,我们在画布上绘制矩形。如果在浏览器中打开它,则应具有以下内容:
使背景动态化
遗憾的是,除了调整 textarea
的大小和一窥Paint API是如何重绘一切的,这大部分还是静态的。所以,让我们通过添加我们可以改变的自定义CSS属性来让事情变得更加动态。
打开你的 styles.css
并在其中添加以下几行:
.pattern { width: 250px; height: 250px; border: 1px solid #000; background-image: paint(pattern); + --pattern-color: #FFCC00; + --pattern-size: 23; + --pattern-spacing: 0; + --pattern-shadow-blur: 10; + --pattern-shadow-x: 10; + --pattern-shadow-y: 1; }
你可以通过在CSS属性前加上 —
来定义自定义CSS属性。这些属性可以被 var()
函数使用。但在我们的案例中,我们将在我们的paint worklet中使用它。
在CSS中检查支持
为确保支持Paint API,我们还可以检查CSS中的支持。为此,我们有两个选择:
-
使用
@supports
规则守护规则。 -
使用后备背景图片。
/* 第一种选择 */ @supports (background: paint(pattern)) { /** * 如果该部分得到评估,则意味着Paint API 支持 **/ } /** * 第二种选择 * 如果支持Paint API,后一条规则将覆盖第一条规则。 * 如果不支持,CSS将使其无效,并将应用url()的规则。 **/ .pattern { background-image: url(pattern.png); background-image: paint(pattern); }
访问绘画worklet中的参数
要读取 pattern.js
中的这些参数,您需要向定义paint worklet的类中添加一个新方法:
class Pattern { // `inputProperties`方法返回的任何东西,paint worklet都可以访问。 static get inputProperties() { return [ '--pattern-color', '--pattern-size', '--pattern-spacing', '--pattern-shadow-blur', '--pattern-shadow-x', '--pattern-shadow-y' ]; } }
要在 paint
方法内部访问这些属性,可以使用 properties.get
:
paint(context, canvas, properties) { const props = { color: properties.get('--pattern-color').toString().trim(), size: parseInt(properties.get('--pattern-size').toString()), spacing: parseInt(properties.get('--pattern-spacing').toString()), shadow: { blur: parseInt(properties.get('--pattern-shadow-blur').toString()), x: parseInt(properties.get('--pattern-shadow-x').toString()), y: parseInt(properties.get('--pattern-shadow-y').toString()) } }; }
对于颜色,我们需要将其转换为字符串。其他所有内容都需要转换为数字。这是因为 properties.get
返回 CSSUnparsedValue
。
为了使内容更具可读性,我创建了两个新函数来为我们处理解析:
paint(context, canvas, properties) { const getPropertyAsString = property => properties.get(property).toString().trim(); const getPropertyAsNumber = property => parseInt(properties.get(property).toString()); const props = { color: getPropertyAsString('--pattern-color'), size: getPropertyAsNumber('--pattern-size'), spacing: getPropertyAsNumber('--pattern-spacing'), shadow: { blur: getPropertyAsNumber('--pattern-shadow-blur'), x: getPropertyAsNumber('--pattern-shadow-x'), y: getPropertyAsNumber('--pattern-shadow-y') } }; }
现在我们要做的就是用相应的 prop
值替换for循环中的所有内容:
for (let x = 0; x < canvas.height / props.size; x++) { for (let y = 0; y < canvas.width / props.size; y++) { const bgColor = (x + y) % 2 === 0 ? '#FFF' : props.color; context.shadowColor = '#212121'; context.shadowBlur = props.shadow.blur; context.shadowOffsetX = props.shadow.x; context.shadowOffsetY = props.shadow.y; context.beginPath(); context.fillStyle = bgColor; context.rect(x * (props.size + props.spacing), y * (props.size + props.spacing), props.size, props.size); context.fill(); } }
现在回到你的浏览器,试着改变一下。
在DevTools中编辑背景总结
为什么CSS Paint API对我们有用?有哪些用例?
最明显的是,它减小了响应的大小。通过消除图像的使用,你可以节省一个网络请求和几千字节。这样可以提高性能。
对于使用DOM元素的复杂CSS效果,你还可以减少页面上的节点数量。因为你可以用Paint API创建复杂的动画,所以不需要额外的空节点。
在我看来,最大的好处是它的可定制性远高于静态背景图片。API还可以创建与分辨率无关的图像,所以你不用担心错过单一屏幕尺寸。
如果你今天选择使用CSS Paint API,请确保你提供polyfill,因为它仍然没有被广泛采用。如果你想调整完成的项目,你可以从这个 GitHub仓库 [2] 中克隆它。
绿皮书正式版 :经过前两个版本的积累和历经三年的全面重写,这本书终于达成技术剖析和用户体验的完美契合。
广深铸就宏篇 :论深,本书深究JS之所以然,举世无可出其右;论广,本书遍历语义之细部,看罢再无机理之惑。
超语言之思想 :万法归宗异曲同工,剥去JS外壳,本书居高处辨析语言奥义的技术大局观,适用于所有编程语言。
修炼重在重学 :混合App|Node服务端|FaaS云原生|前端智能化时代,回归本质重修这门基础课才能走得更远更快。
参考资料
CSS Paint API: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Painting_API
GitHub仓库: https://github.com/flowforfrank/css-paint
近期文章
DOM API中append和appendChild的三个不同点
你知道Object.entries(),但你还知道有Object.fromEntries()吗?
仅3行核心CSS代码的rate评分组件
使用JavaScript的padStart和padEnd格式化字符串
Vue 3教程(适用于Vue 2用户)
JavaScript vs Dart 两者之间的比较
不要过度使用React.useCallback()
HTML页面生成器:使用JavaScript和Node创建CLI
React.js和Vue.js的语法并列比较
从零开始使用JavaScript制作自己的命令行(CLI工具)
Vue.js中编写更好的v-for循环的6种技巧
如果对你有帮助,还可以 在看、留言、 转发 ,这是对作者最大的帮助。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK