CSS Houdini 号称 CSS 领域最令人振奋的革新。CSS 本身长期欠缺语法特性,可拓展性几乎为零,并且新特性的支持效率太低,兼容性差。而 Houdini 直接将 CSS 的 API 暴露给 开发者 ,以往完全黑盒的浏览器解析流 开始 对外开放,开发者可以自定义属于自己的 CSS 属性。
背景
我们 知道 ,浏览器在渲染页面时,首先会解析页面的 HT ML 和 CSS,生成渲染树(rendering tree),再经由布局(layout)和 绘制 (p ai nting),呈现出整个 页面内容 。在 Houdini 出现之前,这个流程上我们能操作的空间少之甚少,尤其是 layout 和 painting 环节,可以说是完全封闭,极大地限制了 CSS 的灵活性。社区中 sass、less、stylus 等 CSS 预处理技 术 的出现大多都 源 于这个 原因 ,它们都希望通过预编译, 突破 CSS 的局限性,让 CSS 拥有更强大的组织和编写能力。所以慢慢地,我们都不再手写 CSS,更方便、更灵活的 CSS 扩展语言成了 web 开发的主角。看到这样的情况,CSS Houdini 终于坐不住了。
什么是 CSS Houdini?
CSS Houdini 对外开放了浏览器解析流程的一 系列 API,这些 API 允许开发者介入浏览器的 CSS en gin e 运作 ,带来了更多的 CSS 解决 方案 。
CSS Houdini 主要提供了以下几个 API:
CSS PR o PE rties and Values API
允许在 CSS 中定义变量和使用变量,是目前兼容性最好的一个 API;
Layout API
允许开发者编写自己的 Layout Module,自定义诸如 dis play 这类的布局属性;
Painting API
允许开发者编写自己的 Paint Module,自定义诸如 background -i mage 这类的绘制属性。
基础:三步用上 Painting API
1、HTML 中通过 Worklets 载入 样式的自定义代码:
<div class="rect"></div> <script> if ("paintWorklet" in CSS) { CSS.paintWorklet.addModule("paintworklet.js"); } </script>
Worklets 也是 Houdini 提供的 API 之一,负责加载和执行样式的自定义 JS 代码。它类似于 Web Worker,是一个运行于主代码之外的独立工作进程,但比 Worker 更为轻量,负责 CSS 渲染 任务 最为合适。
2、新建一个 paintworklet.js, 利用 registerPaint 方法注册一个 paint 类 rect,定义 paint 属性的绘制逻辑:
registerPaint( "rect", class { stat ic get inputProperties() { return ["--rect-color"]; } paint(ctx, geom, properties) { const color = properties.get("--rect-color")[0]; ctx.fillStyle = color; ctx.fillRect(0, 0, geom.width, geom.h ei ght); } } );
上边定义了一个名为 rect 的 paint 属性类,当 rect 被使用时,会实例化 rect 并自动触发 paint 方法执行渲染。paint 方法中,我们获取节点 CSS 定义的 --rect-color 变量,并将元素的背景填充为指定颜色。ctx 参数是一个 Canvas 的 Context 对象,因此 paint 的逻辑跟 Canvas 的绘制方式一样。
3、CSS 中使用的时候,只需要调用 paint 方法:
.rect { width: 100vw; height: 100vh; background-image: paint(rect); --rect-color: rgb(255, 64, 129); }
这是一个自定义 CSS 背景色属性的 简单 实现,看得出利用 CSS Houdini,我们可以像操作 canvas 一样灵活自如地实现我们想要的样式功能。
进阶 :实现动态波纹
根据上述步骤,我们演示一下如何用 CSS Painting API 实现一个动态波浪的效果:
<!-- index.html --> <div id="wave"></div> <style> # wave { width: 20%; height: 70vh; m arg in: 10vh auto; background-color: #ff3e81; background-image: paint(wave); } </style> <script> if ("paintWorklet" in CSS) { CSS.paintWorklet.addModule("paintworklet.js"); const wave = document.querySelector("#wave"); let tick = 0; requestAnimationFrame (function raf(now) { tick += 1; wave.style.cssText = `--animation -t ick: ${tick};`; requestAnimationFr am e(raf); }); } </script> // paintworklet.js registerPaint('wave', class { static get inputProperties() { return ['--animation-tick']; } paint(ctx, geom, properties) { let tick = Number(properties.get('--animation-tick')); const { width, height } = geom; const in IT Y = height * 0.4; tick = tick * 2; ctx.beginPath(); ctx.moveTo(0, initY + Math.sin(tick / 20) * 10); for (let i = 1; i <= width; i++ ) { ctx.l inet o(i, initY + Math.sin((i + tick) / 20) * 10); } ctx.lineTo(width, height); ctx.lineTo(0, height); ctx.lineTo(0, initY + Math.sin(tick / 20) * 10); ctx.closePath(); ctx.fillStyle = 'rgba(255, 255, 255, 0.5)'; ctx.fill(); } })
paintworklet 中,利用 sin 函数绘制波浪线,由于 AnimationWorklets 尚处于实验 阶段 ,开放较少,这里我们在 worklet 外部用 requestAnimationFrame API 来做动画驱动,让波浪纹动起来。完成后能看到下边这样的效果。
&nbs p;
然而事实上这个效果略显僵硬,sin 函数太过于规则了,现实中的波浪 应该 是不规则波动的,这种不规则主要体现在两个方面:
1)波纹高度(Y)随位置(X)变化而不规则变化
把图按照 x-y 正交分解之后,我们希望的不规则,可以认为是固定某一时刻,随着 x 轴变化,波纹高度 y 呈现不规则变化;
2)固定某点(X 固定),波纹高度(Y)随时间推进而不规则变化
动态过程需要考虑时间维度,我们希望的不规则,还需要体现在时间的影响中,比如风吹过的前一秒和后一秒,同一个位置的波浪高度肯定是不规则变化的。
提到不规则,有 朋友 可能想到了用 Math.random 方法,然而这里的不规则并不适合用随机数来实现,因为前后两次取的随机数是不连续的,而前后两个点的波浪是连续的。这个不难理解,你见过长成锯齿状的波浪吗?又 或者 你见过上一刻 10 米高、下一刻就掉到 2 米的波浪吗?
为了实现这种连续不规则的特征,我们弃用 sin 函数,引入了一个包 simplex-noise。由于影响波高的有两个维度,位置 X 和时间 T,这里需要用到 noise2D 方法,它提前在一个三维的空间中,构建了一个连续的不规则曲面:
// paintworklet.js import SimplexNoise From 'simplex-noise'; const sim = new SimplexNoise(() => 1); registerPaint('wave', class { static get inputProperties() { return ['--animation-tick']; } paint(ctx, geom, properties) { const tick = Number(properties.get('--animation-tick')); this.drawWave(ctx, geom, 'rgba(255, 255, 255, 0.4)', 0.004, tick, 15, 0.4); this.drawWave(ctx, geom, 'rgba(255, 255, 255, 0.5)', 0.006, tick, 12, 0.4); } /** * 绘制波纹 */ drawWave(ctx, geom, fillColor, ratio, tick, amp, ih) { const { width, height } = geom; const initY = height * ih; const speedT = tick * ratio; ctx.beginPath(); for (let x = 0, speedX = 0; x <= width; x++) { speedX += ratio * 1; VAR y = initY + sim.noise2D(speedX, speedT) * amp; ctx[x === 0 ? 'moveTo' : 'lineTo'](x, y); } ctx.lineTo(width, height); ctx.lineTo(0, height); ctx.lineTo(0, initY + sim.noise2D(0, speedT) * amp); ctx.closePath(); ctx.fillStyle = fillColor; ctx.fill(); } })
修改峰值和偏置项等参数,可以再画多一个不一样的波浪纹,效果如下,完工!
总结
以上所述是小编给大家介绍的CSS Houdini实现动态波浪纹效果, 希望对大家有所帮助 ,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
如果你 觉得 本文对你有帮助,欢迎 转载 ,烦请注明出处,谢谢!
总结
以上是 为你收集整理的 CSS Houdini实现动态波浪纹效果 全部内容,希望文章能够帮你解决 CSS Houdini实现动态波浪纹效果 所遇到的问题。
如果觉得 网站内容还不错, 推荐好友。
查看更多关于CSS Houdini实现动态波浪纹效果的详细内容...