Files
workbuddy_skills/oil-ui-pro/references/ornament.md
T

83 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 点缀与特效:SVG 和着色器
这里讲用代码画出来的视觉效果:小到一条手绘下划线、一层颗粒,大到首屏整片流动的渐变、扫过按钮的一道流光、由点阵组成的主视觉。它们能让方向从“配色对了”变成“有生命”;做得粗糙时,就是又一层模型默认的装饰。
## 先问要不要
- **从生成引擎里来。** 效果要能说出属于这个方向的理由:方向的关键词是“信号”,点阵和扫描线才成立;是“流体”,流动渐变才成立。删掉它,方向会少一点自己的东西;删掉后没有区别,就不加。
- **一个主效果,几处回响。** 一页选一个主效果,其余地方只用它的颜色、形状或节奏小声呼应,比如首屏是流动渐变,按钮的流光就用同一组颜色。几种特效各自为政,页面就成了效果展示。
- **不碰内容。** 效果不压在正文、数据和控件上,也不画得像按钮;在它上面的文字,按最差的一帧检查对比度。
- **用代码画。** SVG 和着色器体积小,跟着主题色走,放大也清楚。摄影和复杂插画才用图片,见 [素材](media.md)。
- **质感先来自材质。** 顶尖的产品界面很少用流光、渐变团和着色器,让人记住的多是写实的材质、准确的结果和手感。特效是给少数方向的,不是提升质感的默认手段。
- **产品界面收着用。** 后台和工具的工作区不放持续运动的效果;登录、空状态、完成反馈和品牌页可以放开。
## SVG 能做的几类
| 效果 | 做法 | 要注意 |
| --- | --- | --- |
| 颗粒质感 | `feTurbulence type="fractalNoise"` 生成噪声,`feColorMatrix` 把它染成页面的颜色并控制透明度,写成 data URI 平铺成 `background-image`。细颗粒 `baseFrequency` 约 0.8–0.9、透明度 0.05–0.08;再叠一层约 0.004 的大块起伏,表面就不是均匀色块 | 加 `stitchTiles="stitch"` 避免拼缝。做成固定尺寸的平铺图,不把 `filter` 挂在整页或滚动容器上,否则每次重绘都要重算。只在方向本身有实物材质时加,不当作提升质感的通用补丁 |
| 手绘框、粗糙边缘、大号数字的毛边 | `feTurbulence` 接 `feDisplacementMap`,`scale` 约 1.5–3。同类图形各换一个 `seed`,不要一模一样 | 正文不加;`scale` 太大像坏了。滤镜区域默认只向外留 10%,位移、光晕和投影会被裁掉,给 `filter` 设足够的 `x`、`y`、`width`、`height` |
| 沿弧线或环形排字 | `<textPath>` 配 `startOffset="50%"` 和 `text-anchor="middle"` 居中 | 字放在弧的外侧;放在内侧,字距被挤压,字形会相撞。手机换一套 `viewBox` 重新取景,不只是等比缩小 |
| 下划线、轨迹、连接两处内容的引线 | `path` 加 `stroke-linecap="round"`;缩放时线宽不变用 `vector-effect="non-scaling-stroke"`;描线动画设 `pathLength="1"` 和 `stroke-dasharray="1"`,让 `stroke-dashoffset` 从 1 走到 0 | 引线两端要真的指向内容。让光点沿线流动:用一段短虚线加长间隔,动画 `stroke-dashoffset`,再叠一份模糊的副本当光晕 |
颜色统一用 `currentColor` 或设计变量,让效果跟着主题和深色模式变。
## 着色器能做什么
| 效果 | 核心做法 |
| --- | --- |
| 流动渐变 | 3–5 个颜色点沿各自的慢速轨迹移动,按距离混合;要更像液体,用噪声扭曲坐标再取噪声(domain warping),纹路会像大理石或油彩那样流 |
| 极光和光带 | 在一个方向上拉长的噪声,叠加在深色底上,边缘用渐变遮罩收掉 |
| 虹彩和镭射 | 用余弦调色板 `a + b·cos(2π(c·t + d))` 按角度或指针位置取色,四组参数就能调出整条连续的色带 |
| 流光 | 一条两边柔化的亮带,按 20°–30° 斜角扫过形状,只在形状内部可见 |
| 点阵和半调 | 把画面切成网格,每格按下面的亮度画一个圆点;动起来可以是波纹、指针附近的隆起,或者从点阵慢慢显出一张图 |
| 像素和抖动 | 用 Bayer 矩阵做有序抖动,把颜色压成少数几种,得到一位色屏幕和早期游戏的质感 |
| 跟随指针 | 指针附近的亮斑、扭曲或点阵隆起;指针位置先做惯性平滑,再传给着色器 |
不少效果不需要 WebGL:边框上转圈的流光,用 `@property` 注册一个角度变量,驱动 `conic-gradient`,再用 `mask` 只露出边框;文字上的流光,用 `background-clip: text` 配移动的渐变;跟随指针的卡片光斑,把指针坐标写进 CSS 变量,驱动 `radial-gradient`。只有连续变化的噪声、逐像素计算或大量点阵时,才用着色器。
## 做得高级的关键
**渐变**
- **在 OKLab 或 OKLCH 里混色。** 在 sRGB 里混两种对比色,中间会经过发灰发脏的一段;在 OKLab 里混,中间段仍然饱满。CSS 可以写 `linear-gradient(in oklch, …)`,着色器里先转到 OKLab 再插值。
- **加抖动消色带。** 大面积平滑渐变在 8 位显示上会出现一圈圈色带,暗部最明显。输出前叠一层正负半个色阶的噪声,色带就消失了;把噪声加大到 3–8%,就是颗粒渐变的质感。
- **配色从品牌来。** 紫蓝色的柔光团是最典型的模型默认。从设计变量里取两三个色相,挑一组不常见的搭配,再加结构:光带、点阵、颗粒,而不是再加一团光。
- **光晕不要糊成白块。** 几层光叠加后会超过 1,直接截断会变成一片死白。用 `1 - exp(-x)` 这类曲线把亮部压回来,高光才有层次。
**流光**
- **亮带要窄、边要软。** 宽度约为元素的 15–25%,两侧用 `smoothstep` 柔化。
- **扫过要快,间隔要长。** 单次 600–900ms、缓入缓出;在悬停、出现时播放,或每隔 4 秒以上扫一次。一刻不停地扫,就显得廉价。
- **用提亮的混合方式。** `screen` 或 `plus-lighter` 让流光提亮底色,而不是刷上一层白。浅色底上几乎看不见流光,所以它更适合深色、饱和色或金属质感的表面。
- **只在一个地方扫。** 通常是主按钮或一张主卡片。每张卡都在闪,就没有重点。
**点阵**
- **圆点面积跟明暗走。** 半径按亮度的平方根变化,面积才和明暗成正比,画面读起来才像原图。
- **边缘要抗锯齿。** 用 `fwidth` 和 `smoothstep` 在一个像素的宽度内过渡(WebGL2 直接可用)。硬边的点动起来会闪烁、爬行。
- **防摩尔纹。** 网格尺寸取设备像素的整数倍,或把网格旋转 15°、45°;彩色半调的每个通道用不同角度。
- **没亮的点也画出来。** 屏幕式的点阵,熄灭的点保留很淡的一层,亮的点加一圈柔光,才像真的屏幕。
- **格子大小决定读法。** 每格 6–12 CSS 像素读起来是质感,16 像素以上读起来是图形。
**动起来**
- **速度跟角色走。** 背景的循环慢到十秒以上,读正文时注意不到;交互反馈要在 150–300ms 内响应。
- **指针要有惯性。** 每帧让当前位置向目标靠近一小步(例如 `current += (target - current) * 0.1`),效果才像有重量,不会一抖一抖地跟着鼠标。
- **可以跟滚动绑定。** 把滚动进度作为参数传进去,让效果随阅读推进变化,比独立循环更有叙事感。
## 成本与兜底
- **分辨率按效果选。** 模糊的颜色场按 1 倍或一半分辨率渲染,再用 CSS 放大;点阵、像素和细线要按实际设备像素渲染,否则会糊。
- **不引入 3D 引擎。** 只画一个全屏四边形时,直接写 WebGL 或用几 KB 的小工具库,不为它加载 three.js 这类完整引擎。
- **看不见就停。** 滚出视口时用 `IntersectionObserver` 暂停,标签页隐藏时停掉 `requestAnimationFrame`;`prefers-reduced-motion` 时只画一帧静止画面。
- **先写兜底。** 拿不到 WebGL、上下文丢失(`webglcontextlost`)或设备太弱时,显示同样配色的 CSS 渐变或静态图,页面照常可读。
## 验收
- 截几个不同时刻的画面,不只看第一帧;效果上的文字按最差的一帧检查对比度。
- 100% 和 200% 下看点阵、颗粒和边缘;缩略图里看不出颗粒是正常的。
- 浅色、深色和减少动效三种设置各看一次,再看一次兜底画面。
- 在目标手机上看滚动是否掉帧、机身是否发热。
- 装饰性 SVG 和画布加 `aria-hidden="true"`;承担意思的效果,例如由点阵拼出的标题,另给读屏能读到的真实文字。