用 CSS Houdini 打造像素风组件的边框魔法 —— 解构 pixel-ui 的 PixelBox
✨ 本文是继上一篇介绍像素风组件库 pixel-ui 的延续,这次我们深入聊聊其中的魔法工具 ——
PixelBox背后的 CSS Houdini 技术,看看是如何利用paintWorklet实现灵活可配置的像素风边框、圆角与阴影效果的。欢迎点赞、收藏、评论支持,给组件库来个 Star!⭐️
🔙 回顾一下:什么是 pixel-ui?
@mmt817/pixel-ui 是一个采用像素风格美学打造的 Vue 3 组件库,核心理念是“复古 ✖️ 现代”,结合 NES 时代的像素图形与现代前端技术,包括:
- 使用 Vue 3 + TypeScript 构建
- 采用 UnoCSS 作为原子化 CSS 引擎
- 利用 CSS Houdini 构建自定义图形渲染
- 集成 Playground / Storybook / VitePress 演示和文档
- 支持像素风 按钮 / 卡片 / 折叠面板 / 动画精灵 等组件
其中 PxCard、PxButtonGroup、PxCollapse 等组件都依赖一个核心能力:像素风的边框绘制 —— 这就是我们今天的主角 PixelBox 背后的技术实现。
🎨 什么是 CSS Houdini?
CSS Houdini 是浏览器暴露的一套底层 API,允许开发者 扩展 CSS 渲染机制。它的核心模块之一是:
paintWorklet:通过自定义 JavaScript 绘图函数,实现 CSS 背景绘制,支持响应 CSS 属性变化。
简单理解就是 JS in CSS, 在 CSS 代码中执行类似 canvas 绘制逻辑的 js 脚本
相比传统的 CSS 背景图片或伪元素绘制,Houdini 提供了:
- 动态可控:可以通过 CSS 变量实时传值
- 高性能:在浏览器的渲染管线中执行,无需 DOM 操作
- 可组合性强:可以组合多个 Paint Worklet、继承边框等机制
📦 PixelBox 背后的 pixelbox.worklet.ts 做了什么?
这段 Worklet 脚本是整个 PxCard / PxButton 等组件视觉表现的核心,它负责绘制出那种 NES 风格的边框与阴影。
👇 下面我们分块分析这段核心逻辑:
1️⃣ 注册 Paint Worklet 和输入属性
registerPaint('pixel-box', class {
static get inputProperties(): string[] {
return [
'--px-border',
'--px-border-radius',
'--px-bg-color',
'--px-bg-shadow-border',
// 更多……
];
}
})
这部分定义了这个 Worklet 会监听哪些 CSS 属性。当这些属性发生变化时,paint(ctx, geom, props) 会被调用重新绘制。
属性设计非常灵活,比如:
--px-border: 控制边框像素宽度--px-border-radius: 圆角半径--px-bg-shadow-border: 像素阴影宽度--px-bg-shadow-position: 像素阴影显示位置
2️⃣ 核心绘制逻辑 paint(ctx, size, props)
paint(
ctx: PaintRenderingContext2D,
size: { width: number; height: number },
props: StylePropertyMap
): void {
const { width, height } = size
const pbBorder = getInt(props, '--px-border') * 2
let pbBorderRadius = getInt(props, '--px-border-radius')
// ...其他属性的取值/预处理
ctx.fillStyle = pbBackgroundColor
const startY = pbBorder / 2
const contentHeight = size.height - pbBorder
// button 整体背景区域
let startX
let contentWidth
if (buttonGroupFlag || buttonGroupLast) {
startX = 0
contentWidth = size.width - pbBorder / 2
} else {
startX = pbBorder / 2
contentWidth = size.width - pbBorder
}
ctx.fillRect(startX, startY, contentWidth, contentHeight)
// TODO: 侧边阴影/圆角侧边阴影/圆角边框/多余色块清理/边框绘制
}
在这个函数中,我们可以通过 JavaScript 绘图 API(Canvas)对每一个像素层进行精细控制,从而实现像素感极强的边框结构,还可以根据传入的属性决定阴影位置、按钮组合是否共享边框等。
🧪 实际应用效果
如下图中所示,我们的 PxCard、PxButtonGroup 等组件都调用了:
background: paint(pixel-box);
通过设定对应 CSS 变量即可完全定制组件风格:
--px-border: 3px;
--px-border-t: 3px;
--px-border-r: 3px;
--px-border-b: 3px;
--px-border-l: 3px;
--px-border-radius: 0px;
--px-border-color: var(--px-color-base);
--px-bg-color: transparent;
--px-bg-shadow-border: 3px;
--px-bg-shadow-color: var(--px-button-bg-shadow-color);
--px-bg-shadow-position: bottom-right;
这样每个组件的样式变成了动态渲染的画布,而不是死板的类名或背景图!
✨ 为什么选用 Paint Worklet 而不是别的方法?
| 方法 | 灵活性 | 动态能力 | 性能 | 适合像素风? |
|---|---|---|---|---|
| CSS 背景图 | ❌ 固定图 | ❌ | ✅ | 一般 |
| Canvas 元素 | ✅ | ✅ | ❌(脱离 DOM) | ✅ |
| Paint Worklet | ✅✅ | ✅✅(响应 CSS 变量) | ✅ | ✅✅✅ |
CSS Houdini 的 paintWorklet 是实现像素边框最优雅 + 高效的方式之一!
📦 如何接入 pixelbox.worklet.ts
首先, 出于测试需要, 我在 xxx.worklet.ts文件中统一暴露注册函数并立即执行
export function registerPixelBox() {
if (typeof registerPaint !== 'undefined') {
registerPaint('pixelbox', PixelBox)
}
}
registerPixelBox()
然后在对应 vue 组件处将 Worklet 注册逻辑封装为:
// CSS Houdini Paint Worklet
const paint = () => {
try {
if ('paintWorklet' in CSS) {
;(CSS as any).paintWorklet.addModule(workletURL)
} else {
debugWarn(
COMP_NAME,
'CSS Houdini Paint Worklet API is not supported in this browser.'
)
}
// (CSS as any).paintWorklet.addModule(workletURL)
} catch (error) {
console.error('Error loading Paint Worklet:', error)
}
}
onMounted(async () => {
paint()
})
并在组件库打包时,将这段 Worklet 单独构建成浏览器能识别的 JS 文件。
这里注意,
pixel-ui使用的是*.worklet.ts但是CSS.paintWorklet.addModule('pixelbox.worklet.js')会在 独立作用域 中执行 worklet 文件,相当于 Web Worker 环境, 需要预先编译 ts 文件才能正常使用
开发者只需引入组件,即可自动加载绘制逻辑,无需额外配置。
在这期间, pixel-ui 调研过程中发现常规像素圆角的处理方式大致分为三种
最初仅支持圆角 radius 以斜向像素点形式呈现, 结果在 --px-border-radius 值偏大时会出现表现力较差的问题, 于是限定圆角形式如图三种, 并更新绘制逻辑, 例如 PxButton 由此引入新属性 chubby, 一个更圆的圆角??
不过当前绘制逻辑仍有缺陷, chubby 对各项属性要求, 适配性不高, 请合理使用
🔚 小结:未来计划 & 欢迎支持!
通过本文我们深入了解了 pixel-ui 的 PixelBox 背后的原理 —— CSS Houdini 的 paintWorklet,它赋予了组件边框渲染的无限可能。未来我们还会支持:
- ✅ 像素边框动画
- ✅ 多层投影
- ✅ 像素风边角图标装饰
- ✅ 更多定制化像素风格背景(科幻/自然...)
🧱 项目地址: github.com/maomentai81…
🙌 欢迎大家来个 Star ⭐️,提提 Issue 🐛,一起来打造复古又现代的 UI 库!
📢 关注我,持续分享 Vue 3 + CSS Houdini 等前端高级玩法!
如果你对:
- 像素风组件库
- CSS Houdini / Canvas / Web Animation API
- 自定义渲染系统 / 动画组件开发
感兴趣,欢迎关注我,评论交流,让我们把前端玩出花!🌸