# 14 — 面板动效 Status: resolved Type: task ## 需求 > 给这个壁纸设置添加一些细腻的动画吧 ## 一条原则 **只做解释状态变化的动画**——东西从哪来、去哪了、刚才是哪个变了。 面板是常驻 UI。装饰性的循环动画(呼吸、闪烁、渐变流动)只会让人分心,而且这个面板 每改一个属性就会重画一次,任何"一直在跑"的东西都会变成噪音。所以整套动效里 **没有一条 `@keyframes` 是持续运行的**。 ## 加了什么 | 位置 | 动效 | 它在解释什么 | | --- | --- | --- | | 抽屉 | 曲线改成 `cubic-bezier(.22,.61,.36,1)` | 纯 `ease` 结尾会急停 | | 面板刚滑出 | 逐行错开上移淡入(`--i` × 16ms) | 这些东西是"刚出来"的 | | 条件新出现的行 | 同样的入场,不错开 | 它是被勾出来的 | | 行悬停 | 底色高亮 + 图标放大 1.16 | 指针现在在哪一行 | | 复选框 | 自绘,勾靠 `background-size` 从 0 长出来 | 刚才是哪个开关变了 | | 下拉箭头 | 展开时翻 180° | 列表开着 | | 下拉/取色器弹层 | 缩放 + 上移出现 | 它从按钮那儿长出来 | | 色块 | 悬停放大;确认后弹一下 | 颜色变了但位置没变,不弹容易看不出 | | 重置 | 悬停时图标转半圈 | 这是"复位" | | 确认/取消 | 悬停提亮、按下下沉 1px | 按到了 | | 右边缘把手 | 悬停淡入并左移 2px | 这里能滑出东西 | ## 两个容易做错的地方 ### 入场不能每次重画都重播 `paintProps()` 是 `host.textContent = ""` 然后整块重建。如果入场动画挂在 `#wesim[data-open="1"] .row` 这种选择器上,那么**每改一个属性**——拖一下音量、勾一个开关—— 整个面板都会重播一遍动画,看起来像闪屏。 所以: - **刚滑出**那一下:给根节点打 `data-enter="1"`,520ms 后摘掉。带令牌,连着开关几次 只有最后一次的定时器能摘。 - **条件新出现的行**:`paintProps` 记着上一次可见的属性键,只有新冒出来的才加 `.row-enter`。 那 4 个颜色滑杆是个例外:它们不是属性表里的键(是 WE 内置的),走不到按 key 认新的那套, 所以单独用 `colorOptionsShown` 判一次"上一次它们不在"。 ### 复选框不能用 `::after` 画勾 `` 是替换元素,**伪元素在它上面不生效**。所以勾是一张内联 SVG 背景图, 靠 `background-size: 0 0 → 11px 11px` 长出来(`background-size` 是可过渡属性)。 ## prefers-reduced-motion 整套动效在 `@media (prefers-reduced-motion: reduce)` 里被关掉。这不是可选项: 前庭功能敏感的人会因为界面动而难受,而这套动效对可用性没有任何贡献。 ## 验证 `tools/checks/verify-panel.mts` 第 ⑩ 组,全部通过: - 滑出后 `data-enter="1"`、行上跑的是 `wesim-row-in`、`--i` 是 0,1,2,3,4 - 播完 `data-enter` 被摘掉(不会每次重画都重播) - 勾「显示颜色选项」后,**只有**亮度/对比度/饱和度/色调偏移四行带 `.row-enter` - 复选框 `appearance: none`(确认是自绘的) - 展开下拉 → `aria-expanded="true"` 且箭头 `matrix(-1,0,0,-1,0,0)`(翻过来了);Esc 后复位 - `Emulation.setEmulatedMedia` 模拟 reduce → 动画与过渡时长都降到 ~0 ## 测出来的三个真问题 1. 颜色滑杆走不到 `isNew(key)` 那套,永远不带入场标记(上面已说)。 2. **点开下拉时先把 `aria-expanded` 设成 true,紧接着 `openComboFor` 内部的 `closeCombo` 又把它清掉** —— 顺序反了,箭头永远不翻。改成 `openComboFor` 之后再设。 3. 测试自身:动效那一段先移到远处再移到边缘。前面点过「取消」会把 `armed` 置 false, 而它只有"指针离开边缘"才复位——不先走开一次,合成指针根本打不开面板。 ## 回归 全绿:`pnpm check`、调试服与浏览器冒烟、热更新、四档自包含包 `file://`、静态托管预览、 发布产物里动效代码 0 处(`wesim-row-in` 计数为 0)、6 组渲染与重构前逐像素相同。