可行但需满足三个前提:worklet 文件独立、addmodule() 成功加载、浏览器支持(chrome/edge ≥ 88);常见失败因异步加载未完成、非模块化执行、跨域、注册名不匹配;画正弦波需注意 size 取绘制区域、水平采样步长设 2~4px。

直接用 CSS Paint API 画波浪是可行的,但必须满足三个硬性前提:Worklet 文件得独立、CSS.paintWorklet.addModule() 必须成功加载、浏览器得支持(Chrome/Edge ≥ 88,Firefox 和 Safari 当前仍不支持)。缺一不可,否则 background: paint(wave) 就是白写,控制台只会报 Invalid property value 或静默失效。
为什么 paint(wave) 不生效?常见失败原因
这不是 CSS 写错了,而是底层机制没跑通。最常踩的坑集中在加载和注册环节:
-
CSS.paintWorklet.addModule()是异步操作,但很多人在它还没 resolve 就写了background: paint(wave)—— 此时样式表已解析完毕,worklet 还没注册上,自然无效 - 把 worklet 代码塞进
<script></script>标签里,或用eval/ 字符串拼接方式动态执行 —— 浏览器明确拒绝这种非模块化加载 - worklet 文件跨域(比如本地双击 HTML 打开,JS 路径是
file://)—— 必须走 HTTP(S) 同源服务,或配好 CORS - 注册名(如
"wave")和 CSS 中paint(wave)的名字大小写/空格/符号不一致 —— registerPaint 对字符串完全敏感
registerPaint 里怎么画正弦波?关键参数与陷阱
核心是用 Math.sin() 生成波形点,但直接套用容易出现“波太密”“幅度塌陷”“边缘截断”问题。重点看这三个参数:
-
size是绘制区域尺寸(不是 viewport),别用window.innerWidth—— 它随容器缩放自动更新,更可靠 - 水平采样步长建议设为
2~4px(比如for (let x = 0; x ),太大锯齿明显,太小性能无谓消耗 - 垂直偏移推荐用
size.height * 0.5 + Math.sin(x / frequency) * amplitude,其中frequency控制疏密(值越大越密),amplitude控制起伏(建议 ≤size.height * 0.2,否则出界) - 必须手动闭合路径:
ctx.lineTo(size.width, size.height); ctx.lineTo(0, size.height); ctx.closePath();,否则填充区域不完整
如何让波浪动起来?别碰 animation,改用 inputProperties
CSS 动画无法驱动 worklet 重绘,必须靠属性变化触发 paint() 重入。正确做法是:
- 在 worklet 的
static get inputProperties()中声明监听的自定义属性,例如['--wave-offset'] - HTML 元素上设置该属性:
style="--wave-offset: 0",再用requestAnimationFrame动态更新它 - 在
paint()里读取:const offset = props.get('--wave-offset').value || 0,然后把Math.sin((x + offset) / frequency)套进 y 计算 - 避免用
setInterval更新属性 —— 容易丢帧;优先用requestAnimationFrame+ 时间戳做匀速偏移
真正难的不是画一条波,而是让它响应容器尺寸变化、适配高 DPI 屏幕、不因频繁重绘卡顿。这些都得靠 worklet 内部用 size 做归一化计算,而不是写死像素值。一旦脱离了“固定宽高”的假设,所有坐标和步长都得跟着 size 动态算 —— 这才是 Paint API 的设计本意,也是最容易被跳过的细节。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











