规则加太猛反而更丑:过度约束的四种翻车现场
【免费下载链接】taste-skillAgent skills that give coding agents taste: art direction, reference images and a browser check instead of generic AI pages项目地址: https://gitcode.com/GitHub_Trending/ta/taste-skill
给 AI 编码代理套一份审美规则,最初的想法很朴素:既然模型生成的页面总是"居中大标题 + 三张图标卡片 + 紫色渐变",那就把这些东西全禁掉。taste-skill 正是沿着这条路走到今天的项目:v2 从 247 个 curated 站点(One Page Love、Awwwards Sites of the Day)的研究里蒸馏出一套"无装饰"的 house style,并用真实浏览器里的inspect.mjs去测量,而不是靠提示词祈祷。
但项目自己的文档里写着一句容易被跳过的话:
Taking the ornaments away is only half the job; a page that has lost its labels, rules and cards and gained nothing in their place reads as thin, and blind jurors rightly prefer a richer page with tells over an empty page without them.
(见 SKILL.md 开头 Warning 一节。)
这句话点出了本文要谈的问题:约束是好事,把每条阈值都当成"必须打满的指标",结果往往比不加约束更丑。下面四种翻车,都能在仓库源码里找到具体的判定逻辑。
先把话说明白:规则的定位是"靶心",不是"评分"
在讲翻车之前,得先接受一个不太舒服的数字。项目把自家的检测规则跑在那 202 个可测量的获奖站点上,结果是:中位每个站点有 4 个 FAIL,只有 4% 的站点完全干净(见 research.md §9)。被禁得最多的几项恰恰在获奖站上很常见:标题超过两行 60%、疑似 eyebrow 60%、细线 50%、等宽字体 37%。
同一份研究里还有一组盲测记录:最终轮三个 brief,v2 得分 7.7,无技能基线 7.8,另一个设计技能 7.2(CHANGELOG.md v2 的 "How it was tested")。也就是说,规则的价值不在于把分数顶上去,而在于把"没人做过决定"的页面排除掉。理解了这一点,"加太猛"才不至于被误读成"再加一点就好了"。
翻车一:把装饰全删了,留下一个洞
"去掉卡片、去掉分隔线、去掉阴影"是最容易执行的一条,因为它可以机械地做。问题在于,删掉之后空出来的位置,规则并没有告诉你填什么。SKILL.md的 House rules 末尾只写了一句方向性的话:
Removing ornament leaves space. Never fill it with another ornament. Fill it with scale, with the full content, with a picture made for this subject, or with a field of flat colour.
如果没有做到这一点,检查器会用三组阈值把"空"翻译成"错":
empty-screens:桌面端有2 个及以上屏幕的有效内容(文字、图片或色块)占比低于 20%,直接 FAIL;blank-gap:页面中出现高度超过视口 60% 的纯空白段 FAIL,42%–60% 之间出现两段及以上也 FAIL;lopsided/hero-void:有 2 个及以上区块把内容全挤在一侧、另一侧留白超过 42% 宽度,FAIL;首屏出现一个占屏 28% 以上的空矩形,WARN。
判定逻辑在 rules.mjs 的judgeLayout()里,空白段用的是视口高度的比例,而不是像素:
const big = L.gaps.filter((g) => g.height >= H * 0.6), mid = L.gaps.filter((g) => g.height >= H * 0.42 && g.height < H * 0.6); if (big.length || mid.length >= 2) add(L.stage ? 'WARN' : 'FAIL', 'blank-gap', ...)更严厉的是评论区那套"封顶"机制:critique.md 规定,只要出现"两个及以上几乎空的桌面屏",设计分直接不超过 6.5,无论其他部分多精致。
值得对照的是 layout.md §4 的结论:在 97 个 Sites of the Day 的阅读记录里,读者把每一块大空白判成两种东西之一,"rest"(被某个东西收口)或"hole"(没人收口)。强站也有很多 rest,但大约一半的强站仍然留有至少一个 hole,而 hole 正是访客第一时间会点名的问题。
所以"过度留白"的翻车不是审美判断,是可测量的:删掉装饰之后,若没有把尺寸做大、内容写满、或把这一块交给一张属于这个主题的图片,检查器量到的就是洞。项目自己在 tells.md §8 给这种状态起了名字,叫 "avoidance aesthetic":任何人只要知道类别加上一份禁止清单,都能猜出这个页面长什么样。
翻车二:为了不被判"太静",把动效堆上去
动效这条最容易踩进"指标化"的陷阱,因为它是整套规则里唯一带下限的:inspect.mjs里写着
const MOTION_MIN = 8, MOTION_GOOD = 16; // distinct moving elements over load + one scroll through the page加载与滚动过程中实际发生位移的元素少于 8 个,still-pageFAIL;少于 16 个,WARN。而研究给出的获奖站中位数是每页 130 个元素被脚本移动(motion.md §2)。一个刚被"禁掉一切"的页面,很容易在这个数字上恐慌,于是往每一块上加同一个 fade-up。
但这恰好撞上另一条明令禁止的规则:"同一个 fade-and-slide-up 打在所有区块上"是生成页动效最典型的 tell,被点名最多的就是它;"首屏十几个错峰入场"同样被禁。真正的要求是结构化的五件事:两三个滚动场景、一个 signature move、每个区块按阅读顺序编排的入场(错峰 60–90ms,位移 16–32px)、控件反馈、一张会动的图片。
堆叠的代价在场景检查里立刻显形:
| 检查项 | 阈值 | 后果 |
|---|---|---|
many-scenes | 一页超过 4 个滚动场景 | WARN,要求砍到两三个 |
scene-heavy | 场景占位合计超过页高的 60% | WARN,要求缩短停留 |
long-pin | 同一段大字连续占据 3 屏以上 | WARN |
empty-screens | 空转的 pinned 舞台留下的空白 | FAIL |
这些判定写在 inspect.mjs 的场景与帧检查段里。它们共同指向一个事实:动效的预算是守恒的。你把 20 个区块都做成入场,signature move 就不再是"那一个记得住的动作",而只是第 21 个渐显;你把 6 个场景塞进一页,每个场景能分到的阅读间隔就被压到零,scene-heavy会替读者说出"这里太挤"。
翻车三:配色往两头拉,都会失衡
配色是"过度约束"最容易被误读成"禁用列表"的地方。rules.mjs用一个 HSL 区间函数把三类颜色家族打成生成页签名:
export function colourFamily(hsl) { const { h, s, l } = hsl; if (inRange(h, 22, 62) && s >= 0.16 && l >= 0.88 && l < 0.995) return 'cream'; if (inRange(h, 6, 30) && s >= 0.38 && s <= 0.85 && l >= 0.42 && l <= 0.72) return 'terracotta'; if (inRange(h, 244, 295) && s >= 0.42 && l >= 0.3 && l <= 0.8) return 'ai-purple'; return null; }组合起来就是几条硬门:cream + terracotta 同时出现 FAIL,terracotta 单独出现也 FAIL,紫/靛 FAIL,任何渐变填充 FAIL,静止元素上的阴影 FAIL,1px 描边盒子 ≥3 个 FAIL。把这份清单当 KPI 执行,最省事的做法是把页面调成一片灰。
然后就会触发另一侧的阈值:grey-body。检查器会算运行正文与背景的对比度,低于 7:1 就 WARN,提示语写得很直白:"the running text is a soft grey on its ground… pages read thin and unfinished when everything is grey"。同类还有应用屏那边的no-data-hue:如果一张带图表的屏幕上完全没有色相,而彩色像素占比低于 0.2%,会提示把风格里唯一的那支图表色放到主数据上。
真正的约束从来不是"少用颜色",而是比例。colour.md §3 给的是份额:
- 底色(ground)占 70%–90%;
- 墨色承担文字,也许再承担一个反色区块;
- accent 在任一屏幕上不超过 5%,它标记动作和至多一个重复元素;
- 表面用 2–6 个亮度点的一步色阶区分,不用线,也不用阴影。
应用屏那边还有一条具体的预算:首屏强彩色像素超过 12% 就 WARN(colour-sprawl),研究里被测的真实产品屏大多在 3% 附近。约束的意图是"把颜色花在数据上",不是"不许有颜色"。把 5% 理解成 0%,就是从"AI 紫"翻到"施工图"。
翻车四:层级被两头拉断
字号是最容易被"拉满"的参数。想显得有冲击力,就把 display 拉到 9vw;想显得克制,就把所有文字压到 15–16px。两条路都会失败,因为检查器是双向夹的。
往大拉:headline-lines规定任何标题在任何宽度下超过 2 行就是 FAIL(陈述段落按 statement 尺寸处理,桌面 ≤36px、平板 ≤32px、手机 ≤24px,可放宽到 3–4 行)。而且修法顺序被写死在给代理的提示里:先砍字,再放宽 measure,最后才降字号,且不得低于已选定的 scale。
往平压:focal-point会量首屏最大字号占视口宽度的比例(hero.vw)以及最大图片占视口的比例,两者都不够、又没有真实界面片段时 FAIL:
else if (!mobile && m.hero.vw < 4.5 && (m.heroMedia[0]?.ratio || 0) < 0.3 && !m.page.uiFragments) { add('FAIL', 'focal-point', ...); }研究数据支持这条:最强站点的最大字号中位数是 8.4vw,弱站是 5.0vw(type.md §1)。同时另一头还有size-count:一页出现超过 9 个不同字号就 WARN;条目里的建议是"一页大约五个:display、heading、lead、body、small"。而body-size卡在 15px 的下限(低于 15px FAIL,16px 以下在桌面 WARN)。
于是就有了一个典型的两难:字号种类被压到 5 个以内,display 又被要求大到 8vw 量级,那么"显示级与正文级之间至少 4 倍"的落差就必须靠极少的几级完成,中间任何一级"顺手加个 20px"的小标题,都会同时踩到size-count和层级扁平化。这也是 critique.md 第 6 条 pass 的原话:从正文到标题的跳跃要"decisive(三倍以上)"。
参数上限为什么不能一起拉满
把上面四段合起来看,会发现一个结构性的事实:这些阈值不是独立指标,而是成对的下限与上限,中间只有一条窄带。
| 你想优化的目标 | 拉满时触发的检查 | 反向拉满时触发的检查 |
|---|---|---|
| 留白/克制 | empty-screens、blank-gap、lopsided | 装饰回归:gradient、shadow、icon-cards |
| 动效表现力 | many-scenes、scene-heavy、long-pin | still-page(<8 FAIL,<16 WARN) |
| 色彩克制 | grey-body、no-data-hue、无 accent 的扁平感 | palette-purple、palette-claude、colour-sprawl |
| 字号冲击力 | headline-lines、overflow | focal-point、size-count、body-size |
更麻烦的是,修一个 FAIL 常常会打开另一个。删掉三张图标卡片,那一段就变成lopsided或blank-gap;把空白填上一张图片,可能让few-pictures过关,却让某一屏变成"6 张小图"从而在 critique 的第 2 条 pass(眯眼测试)里被判成"全是中等质量、没有主角";给页面加动效躲开still-page,又可能因为入场动画没触发而留下空带,直接命中reduced-hidden或empty-screens。
这就是"参数不能一起拉满"的工程含义:规则内部有一个隐含的预算,总量是守恒的。研究给出的获奖站画像本身就是这种平衡的产物:图片中位数 7 张(头部 8 张,最低 2 张),但 42% 的屏幕一张图都没有、19% 的屏幕 90% 以上是图(research.md §12)。它不是"均匀铺满",而是"少数屏幕承担全部视觉重量,其余屏幕留白"。
还有一层:--allow这个开关是按规则 id 全域豁免的。你在某一次构建里为了省事放行hairline,之后这个页面上所有细线都不再被计量。工具没有变弱,是仪表被关掉了。
回退策略与灰度验证
项目对"规则和判断冲突"这件事,给了一套相当克制的处理流程,可以直接当团队的灰度方案用。
第一,重抽要有理由,且必须记账。draw.mjs抽出的方向表(direction sheet)默认要求"采纳,不要和你本来就会做的布局混合"。只有当三种情况之一成立时才允许--redraw:与已声明的品牌约束冲突、需要并不存在的素材、某个 section 装不下真实内容。原文明确加了一句:"Never redraw to get something more comfortable"。每次重抽都会写进direction.json的redraws计数,并在最终报告里说明。
第二,豁免要单条、要留痕。品牌自带紫色时,正确做法是保留品牌资产、在报告里说明,并且只对那一条规则传--allow palette-purple;而不是把整个调色板检查关掉。inspect.mjs会把allow列表写进report.json,读报告的人知道哪些门是开着的。
第三,验证要分层,且必须在"出货态"上做。检查器默认跑 1440 / 768 / 390 三个宽度,并在 1.2 秒后确认首屏标题真的可读(late-titleFAIL)。2.1.5 加入的dev-server警告值得单独提:如果检测到 Vite / webpack / Next 的开发服务器,会提醒你在 production build 上再跑一次。这条来自真实问题:构建工具会把backdrop-filter之类的东西裁掉,dev server 上看到的不是访客拿到的东西(CHANGELOG.md 2.1.5)。
第四,也是最便宜的一次回退演练:prefers-reduced-motion。检查器会另开一个 reduced-motion 的页面,扫描首屏文本,只要有 2 段以上因为等待动画而不可见,就 FAIL(reduced-hidden)。所有隐藏初态都必须写在@media (prefers-reduced-motion: no-preference)里,reduced 状态就是完成态。这条规则的实际效果是:如果你的动效层撤掉之后页面塌了,说明它本来就靠动效撑着。
第五,改版要有 before/after 两个目录。对已有页面做 restyle 或 redesign 时,流程要求先把现状inspect到.taste-skill/before,改完再 inspect 到.taste-skill/after,在三个宽度上并排比较,并逐条点过原来能用的链接、表单和菜单。修复顺序也是固定的,因为后面的项救不了前面的项:想法 → 层级 → 构图 → 字体 → 图像 → 颜色 → 细节 → 动效。
第六,给自己设止损。critique 最多三轮,每轮只修最显眼的三个问题;第三轮如果仍然低于 7.5,报告里要如实写出剩余问题,不许四舍五入。同理,inspect.mjs通过只代表"没有测到被禁的东西",原文的说法是 "Passing the meter is the floor, not the grade"。
第七,把规则本身当代码测。仓库的tests/目录里有针对 frontmatter 解析、检查器文件命名、文本编码和浏览器 profile 清理的测试。规则一旦写进 CI,就不容易在"这次先放过"的临时妥协里腐化;而 2.1.2 的事故(描述字段里一个未加引号的:让整个 skill 被静默丢弃)说明这类测试是必要的。
收尾:约束的对象是"决定",不是"数量"
回头看那三个曾经常被引用的旋钮DESIGN_VARIANCE/MOTION_INTENSITY/VISUAL_DENSITY(现在只保留在 v2 experimental 的历史说明里),它们的直觉是"参数越高越有设计感"。但 v2 的实践恰好相反:真正拉开差距的不是把某一维推到 10,而是每一维都被推到它该在的位置,并且彼此不打架。
四种翻车的共同点,是把"避免某种丑"误当成"达成某种美"。删装饰避免了模板味,却可能造出空洞;加动效避免了静态感,却可能造出噪音;禁颜色避免了 AI 紫,却可能造出施工图;放大字号避免了平庸,却可能造出断掉的层级。rules.mjs里的每一条 FAIL 都只是一道门,门后面的房间长什么样,仍然要靠在截图前坐着看完十四个 pass 的人来决定。
项目自己的盲测结果是最好的注脚:规则齐备的 v2 是 7.7,什么技能都不给的基线是 7.8。约束能稳定下限,但顶不上限。把规则加猛之前,先确认自己还在做设计,而不是在做合规。
【免费下载链接】taste-skillAgent skills that give coding agents taste: art direction, reference images and a browser check instead of generic AI pages项目地址: https://gitcode.com/GitHub_Trending/ta/taste-skill
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考