九月底我做了个小工具,叫捞帧。
输入一个词,它把全网的图和视频捞一遍,按色卡、风格、用途分好类,顺手给一张联系表。
![]()
功能两三天就写完了。前端花的时间比后端多好几倍,token 也烧得凶。
问题也出在这儿。
我跟它说得最多的一句话是「再高级一点」。
这句话说了很多遍,每遍的意思都不一样。它每次都照做,改完更花,再改,更花。
后来我把整个过程复盘了一遍,发现卡点特别没意思。
那句话根本没法执行。
八成的不高级,都出在加动效之前。而大多数人把动效当第一道工序。
先判层,再动手
整个项目最核心的一句判断写在这里。
八成「不高级」死在第一层。
层有三层。第一层叫静态设计层,症状是乱、挤、廉价、没重点、像模板,该改的是层级、留白、字阶、对比、对齐。第二层叫动效层,症状是死板、突兀、跳,该改的是时序、缓动、编排、状态过渡。第三层叫平台层,症状是真卡、掉帧、手机错乱、键盘用不了,该改的是属性选择、API 选型、降级。
误判层是最大的浪费。给一个没有层级的页面加弹簧动画,等于在歪地基上贴瓷砖。
![]()
这张对照图是项目里自带的一次真实走查。左边那份命中「廉价感诊断清单」5 条,全站 16px 没有字阶、全部居中、纯黑纯白、圆角 6 与 10 混用、0 0 20px rgba(0,0,0,.5) 硬阴影。
这一份加任何动效都只会更廉价,必须先修静态层。
形容词换成数值
高级这两个字不可执行。32px、字重 600、色值 #1B3A2E 可以。
同一个卡片列表,改前改后是这样的。
| 项 | 改前 | 改后 | 依据 |
| 主标题 | 16px / 400 | 32px / 600 / #1B3A2E | 主标题等于正文的 2 到 2.5 倍 |
| 正文 | 16px / #000 | 14 至 15px / #6B6B66 | 次要信息压到 60% 灰 |
| 区块间距 | 16px 等距 | 组间 28、组内 12 | 邻近性,组间距至少是组内的 2 倍 |
| 背景 | #FFF | #FAF8F5 | 纯白显廉价 |
| 圆角 | 6 / 10 / 14 | 8 / 12 / 999 | 全站三档,不出现体系外值 |
| 阴影 | 0 0 20px rgba(0,0,0,.5) | 0 1px 2px rgba(44,44,42,.05) | 取 5 级阴影里最轻一档 |
动效那边同样。调性由三个旋钮决定,拧完旋钮再挑效果,反过来做会得到什么都有但完全不统一的东西。
| 旋钮 | 克制 | 标准 | 强烈 |
| 幅度 | 位移 2 至 4px | 位移 8 至 16px | 位移 24 至 40px |
| 时长 | 0.15 至 0.25s | 0.3 至 0.4s | 0.5 至 0.8s |
| 缓动 | linear | ease-out | spring |
落在具体数值时读动效 token 表,里面有 duration、easing、spring 三组,对齐 Material 3。同一个动作全站必须用同一个 token,这是看起来最专业最便宜的来源。
词库里有 68 条效果,每条给中英双名。英文名是关键,「悬停上浮 Hover Lift」这种写法,AI 一次就写对了。
技术栈分了四档,默认从最轻的起,做不到才升级。判断口径写得很死。能在 CSS 里写出来的,不要上 GSAP;能拍成照片的,不要上 three.js;能用设计稿交付的,不要上 p5.js。
十种方向,一张映射表
「要有点杂志感」跟「高级一点」是同一类废话。
所以做了十种艺术方向的完整规格,瑞士国际主义、包豪斯、构成主义、Art Deco、编辑排版、粗野主义、极简、孟菲斯、Y2K、印刷质感。每种都写明栅格、字重、字体、色彩、动效时长与缓动。
![]()
最实用的一张表是流派到动效的映射。
| 流派 | 时长 | 缓动 | 位移 | 禁用 |
| 瑞士 | 200 至 300ms | power2.out | 不超过 8px | 弹跳、旋转 |
| 构成主义 | 120 至 200ms | steps() | 大位移斜切 | 慢速淡入 |
| Art Deco | 400 至 600ms | power2.inOut | 遮罩展开 | 快速切换 |
| 粗野主义 | 0 至 80ms | 无 | 瞬时 | 任何缓动 |
| 极简 | 500 至 800ms | power1.inOut | 不超过 6px | 位移、旋转 |
瑞士风的页面配孟菲斯的弹跳缓动,一眼假。
一张卡六个格子
每个组件按六格写,撕线面板举个例子。
| 格 | 内容 |
| 静止态 | 底部 1.5px 金色虚线撕口,28px 抓取区,居中 40×3 把手 |
| 状态机 | closed 到 dragging,到阈值 72px,open 或回弹 |
| 参数 | 跟手阻尼 0.55,回弹 cubic-bezier(.34,1.4,.64,1) 320ms |
| 降级 | reduced-motion 去掉回弹,改 180ms 线性 |
| 验收 | 拖一半松手必须回弹,不能卡在中间态 |
| 常见做错 | 用 border-bottom: dashed,虚线间距不可控 |
组件一共 40 个,分容器与空间、输入与选择、反馈、导航、数据五类。其中 16 个做成了可直接打开操作的页面。
![]()
![]()
文档最后给了一套六格拆解法,配三个通用套路,拖拽类、形变类、序列类。目录只是起点,遇到新组件照着填就能拿到同等级的规格,而不是又写一句「加个过渡效果」。
拿自己的尺子量自己
交付前有个脚本要跑。零依赖,检出 8 类问题,退出码能直接接 CI,有 error 返回 1,干净返回 0。
我拿它扫了捞帧的线上产物。
![]()
三条 error 都挺典型。transition-property 里写了 left、right、width,这是每帧触发重排;transition-property 直接写 all,会把不相干属性一起过渡;文件里有 4 处 will-change,图层可能过多。
这是我自己做的产品,用我自己写的尺子量的,还是量出 3 个 error。
顺手也量了好的地方。这份 CSS 422KB,transition 写了 157 处,prefers-reduced-motion 8 处,focus-visible 30 处,动效 token 用的是自定义变量。这些 lint 不挑,它只挑能确定的那几类。
评审这边是另一套尺子。六个维度各 0 到 4 分,满分 24。18 分以上可交付,12 到 17 修完再交,12 以下重做。
其中有一条规则比分数本身狠。任何一个维度打出 0 分,一票否决,总分再高也不行。
案例里那张卡片列表,改前 5 分,改后 23 分。改前「层级与节奏」和「降级与无障碍」两项都是 0 分,按规则直接否决,分数再高也没用。
理由是,一个页面可以整体看起来不错,但只要有一项彻底失能,那一项就会在真实使用里暴露出来。
先眯眼三秒
这个项目一天发了三个版本,1.0.0 到 1.2.0。50 个文件,MIT,两个零依赖脚本,28 个测试。同步挂在 GitHub 和 AtomGit 上,WorkBuddy 技能市场能搜到。
它不替我做设计判断。它只做一件事,把说不清的那句话逼成能验收的数值。
以后再听到那句「再高级一点」,我打算先眯眼三秒,看能不能分出主次。
分不出来就先别动排版,动效放最后。