悬浮岛 + 光场 · 后台 UI 风格复刻
设计语言一句话:
光是指示注意力的工具,不是装饰。
每当你想再叠一处光,先问一句「它在提示什么?」——答不上来就别加。 这条判据能挡掉九成的「花哨但廉价」。
零、怎么用这份技能(先读完这一节)
这份技能的正文是入口与地图,具体做法在 references/ 下按需读取。
不要凭记忆写代码 —— 每一步动手之前,先读那一步指定的文件。
huein-lightfield-ui-style/
├── SKILL.md ← 你正在读的:原则 · 七步流程 · 骨架 · 地图
├── references/
│ ├── 01-tokens.md 设计 token 全表与色相派生推导
│ ├── 02-shell.md 悬浮岛外壳:几何 / 收起展开 / 窄屏 / 首帧 / 滚动 / 缓存
│ ├── 03-light.md 光:边缘光 / 光柱 / 点阵 / 三层光场 / 开场动画
│ ├── 04-motion.md 导航飞行 · 展开过渡 · 内容浮入
│ └── 05-verify.md 验收与取证手法(怎么写断言 · 测试脚本的坑)
├── assets/
│ ├── tokens.css ← 可直接改用(MIT,见 LICENSE)
│ └── lightfield.js 光场引擎,851 行,可直接改用
├── PROMPT.md 给 AI 的一键复用提示词(复制粘贴用)
└── README.md
硬规则(不遵守会做错)
- 按顺序做,不要跳步。 七步的顺序是设计过的 —— 后一步假设前一步已经就位。
- 每一步动手前读对应 reference,尤其是
01-tokens.md和05-verify.md。 - 每一步做完就自检,不要攒到最后一起验。断言怎么写见
references/05-verify.md。 - 一次只改一小块。 这种风格几乎全是动效与光,一次性铺开改, 出问题时无法定位是哪一步引入的。
.standalone.md(如果仓库里有SKILL.full.md)是所有文件的拼接版 —— 只有在「只能粘贴一个文件、读不到references/」时才用它。 能用references/就一定用,按需读取比全文照读省得多。
如果你读不到 references/(只拿到了这一份文本):
信息量仍然够开始第 1、2、4、5 步 —— 本文件里有原则、流程、骨架、和三处最贵的坑。
动手写 light() 之前先说明「缺了光场那部分的细节,我按骨架里描述的三层镜像模型实现」,
不要硬编。
一、三条原则
- 光有方向。 所有光层对同一个「光场焦点」做响应(桌面 = 指针,触摸 = 漂移的虚拟点)。 绝不要出现两个各自为政的光源 —— 那是「装饰」的味道。
- 深色是主场景,浅色不是反色。 两套独立调校: 浅色下光场 chroma 降一档、玻璃换实色、文字加粗。 直接反相或简单换亮度会立刻露出廉价感。
- 动效只动
transform与opacity,绝不回弹。 「呼吸感」来自错峰 + 时长,不是来自花哨的曲线。会弹的缓动一律不用。
二、从零复刻 · 七步
| # | 做什么 | 读哪一份 | 做完的样子 |
|---|---|---|---|
| 1 | 定 token:色相派生、间距、圆角、字号、动效阶梯 | references/01-tokens.md |
改一个 --brand-hue 能派生整套协调配色 |
| 2 | 搭外壳骨架:grid + 一圈等宽留白,做出两个互不接触的悬浮岛 |
references/02-shell.md §一 |
侧栏与顶栏之间有一条等宽缝,四周留白相等 |
| 3 | 收起 / 展开:侧栏收成图标栏、顶栏浮走并把纵向空间还回来 | references/02-shell.md §四 |
两个方向都能收,且收起来真的省出了空间 |
| 4 | 首屏入场 + 解析期状态 + 动画残留清理 | references/02-shell.md §二 §三 §五 §八 |
刷新后第一帧就是正确状态,静置后无残留 transform |
| 5 | 导航切换的「滑过去」+ 可展开内容的过渡 | references/04-motion.md |
选中项从旧项滑到新项,中途没有暗缝 |
| 6 | 光:先边缘光(距离驱动),再光标光柱,最后点阵的面具 | references/03-light.md |
指针不碰卡片也能点亮它的边 |
| 7 | 内容依次浮入 | references/04-motion.md 后半 |
内容一块块从雾里凝出来,错峰不挤在一起 |
第 4 步的「解析期状态」和第 6 步的「开场动画」是最容易被跳过、也最容易返工的两处 —— 它们都涉及「第一帧长什么样」,事后补的代价很高。
三、页面骨架(照抄,顺序都不要改)
<body>
<!-- ① 底色:三层光 + 点阵。fixed,最底,不吃事件 -->
<div class="lightfield">…</div>
<!-- ② 侧栏的边光:因为侧栏是滚动容器,光不能挂在它自己身上 -->
<div class="island-glow"></div>
<!-- ③ 光标光柱:fixed + mix-blend-mode: screen -->
<div class="cursor-light"></div>
<div class="shell">
<aside class="sidebar">…</aside>
<div class="shell__main">
<header class="topbar">…</header>
<main class="shell__content">…</main>
</div>
</div>
</body>
三条铁律(这三条是这套风格里最贵的知识)
① 所有 fixed 层必须在内容区之外。
animation-fill-mode: both 的终态不是 none —— computed 的 transform 是矩阵、
filter 是 blur(0px),两者都会让元素成为 position: fixed 后代的包含块。
把遮罩、ghost、toast 放进内容区,它们会塌成一条横条贴在页面下半部分。
→ 推论:动画播完必须撤掉 animation。
② 滚动容器上的光要另开 fixed 层。
挂在滚动容器自己身上会跟着内容一起滚走,而且不滚动的时候看不出问题。
③ 解析期状态一律用内联脚本。
主题、折叠状态、导航起手、滚动位置这些「来自 localStorage / sessionStorage」的状态,
必须在 <head> 或 body 末尾的内联脚本里就应用 ——
模块脚本是 deferred,跑到之前浏览器已经画过几帧,用户会看到「先闪一下再变」。
四、这套风格里最容易做错的三个地方
先记住这三条,能省掉一整轮返工。细节见对应 reference。
- 三层光场是「围绕焦点做镜像」,不是三个固定锚点。
主光(品红)在焦点 · 补光(琥珀)对角镜像 · 冷光(靛紫)垂直镜像。
⚠️ 写错成「三个固定锚点 + 微视差」的后果是:三团光全挤在屏幕上方一条横带、下半屏纯黑。
参数都在、不报错、注释还理直气壮 —— 看代码根本看不出错。 →
references/03-light.md - 光由「距离」决定,不是「碰到才亮」。
距离要用「到矩形本身的精确距离」(矩形内 = 0),
不是「到中心距离 − 外接圆半径」(那会让指针在下半个屏幕都被判成贴着顶栏)。
→
references/03-light.md - 生硬通常出在「时序」,不在曲线。
凡是「A 已经到位、B 还在路上」,调 B 的曲线永远调不好 —— 要把 A 按住。
→
references/04-motion.md
五、做完的样子(Definition of Done)
全部按 references/05-verify.md 的方式写成断言,不靠肉眼看。至少要能证明:
- 四周留白相等、两个岛不接触(缝 = gap)
- 收起态刷新后,第一帧就是收起态(不是先展开再折一下)
- 首次加载有入场动画;第二次加载没有,且静置后
transform/clipPath都是none - 导航切换:滑块起点贴着旧项(< 16px)、终点贴着新项(< 16px)
- 落地过程逐帧采样「两层 opacity 的叠加」恒为 1(没有暗缝)
- 指针不碰卡片时
--gle也 > 0(距离驱动),且随距离单调递减 - 点阵面具的第一个圆的位置 == 光场写出的
--lf-fx / --lf-fy - 刷新 / 换页时,光场起点接的是上一页的位置
- 全站没有「引用了但不存在的 CSS 变量」(这个坑会让边框变成白框,且不报错)
- 控制台无
pageerror
附:这份技能的来历
从 绘影工作台 hueinbench(自媒体工作室管理系统,AGPL-3.0) 里把这套界面风格抽出来的一份复刻手册。原项目里这套设计已经跑过 13 个版本迭代, 下面每一条「⚠️」基本都是真实踩过的坑,不是推演出来的。
本仓库以 MIT 开源,见 LICENSE。作者同为绘影工作台的作者,
故本仓库中的 assets/(与该项目同源)在此按 MIT 另行授权。