1. 从“impeccable”说起:一个被低估的前端设计关键词
第一次看到“impeccable”这个词被拿来命名一个前端设计相关的项目,我的反应是:这名字起得挺狂。impeccable,中文意思是“无可挑剔的、零瑕疵的”。一个做前端设计工具或者设计规范的项目敢叫这个名字,要么是标题党,要么是真有两把刷子。我花了一些时间去研究这个方向上的实践,发现它背后指向的其实是一个非常具体的痛点:AI coding agents 生成的前端界面,离“无可挑剔”到底还差多远?
如果你最近半年在用各种 CLI 工具辅助写前端代码,比如用 codex cli、claude code 这类工具生成 React 组件、Tailwind 样式或者完整的页面布局,你大概率有过这种体验:代码能跑,逻辑没错,但界面就是“差点意思”。间距不均匀、颜色对比度不够、响应式断点处理得粗糙、hover 状态缺失、focus ring 被干掉、动效生硬。这些问题单个拎出来都不致命,但叠在一起,用户一眼就能感觉到“这不是一个成熟产品”。
“impeccable”这个项目标题,结合 AI coding agents、frontend design、CLI、browser extension 这几个热搜词,我判断它要解决的核心问题是:如何让 AI 编码代理在前端设计层面达到“无可挑剔”的输出质量。这不是一个单纯的代码生成问题,而是一个设计系统、约束规则、验证反馈三者结合的工程问题。
这篇文章我会从几个层面拆解:为什么 AI 写前端总是“差一口气”、impeccable 这类方案的设计思路是什么、CLI 和 browser extension 在其中扮演什么角色、具体怎么落地一套可复用的前端质量约束流程,以及我在实操中踩过的坑和总结出来的排查技巧。适合正在用 AI 辅助前端开发、或者正在搭建团队前端规范体系的同学参考。
2. AI 写前端为什么总是“差一口气”
2.1 代码正确不等于设计正确
AI coding agents 的训练目标本质上是“生成能通过测试的代码”。对于后端逻辑,这个目标相对明确:输入输出对得上、边界条件处理好、性能达标,基本就算合格。但前端不一样。前端代码的“正确性”有两个维度:功能正确性和视觉正确性。前者 AI 已经做得不错了,后者才是真正的短板。
我做过一个简单的测试:让几个主流 AI 编码工具分别生成同一个需求——“一个带搜索框和筛选标签的卡片列表页”。功能层面,所有工具都能在几十秒内给出可运行的代码。但视觉层面,差距非常明显。有的工具生成的卡片间距是p-4,有的是p-6,有的甚至混用;搜索框的 placeholder 颜色有的用默认灰色,有的硬编码了一个低对比度的颜色;筛选标签的选中态有的用背景色变化,有的只改了文字颜色,有的干脆没有选中态。
这些细节,人类设计师会本能地处理,因为他们在脑子里有一套“设计系统”在运行。AI 没有这套系统,它只是在概率上生成“看起来像那么回事”的代码。
2.2 设计意图的丢失发生在哪一步
问题的根源在于:设计意图在从需求到代码的转换过程中被稀释了。你给 AI 的 prompt 可能是“做一个简洁现代的卡片列表”,但“简洁现代”这四个字在 AI 的理解里是模糊的。它不知道你的项目用的是 4px 还是 8px 的间距基数,不知道你的品牌色是哪个色号,不知道你的圆角规范是rounded-lg还是rounded-xl,不知道你的阴影层级有几档。
我试过在 prompt 里把这些都写清楚,结果 prompt 变得巨长无比,而且每次生成都要重复一遍。更麻烦的是,即使你写清楚了,AI 也不一定严格遵守。它会在某些地方“自作主张”,比如觉得某个按钮用rounded-full更好看,或者觉得某个间距用p-3更合适。这种“创意发挥”在后端代码里可能是好事,在前端设计里就是灾难。
2.3 现有工具的局限性
目前市面上解决这个问题的思路大概分三类。第一类是设计系统文档,比如 Storybook 或者自建的设计规范站点,但这类工具是给人看的,AI 不会主动去读。第二类是代码模板,比如 shadcn/ui 这种组件库,AI 生成时可以直接引用,但模板覆盖不到所有场景,而且 AI 经常“忘记”用模板。第三类是Lint 规则,比如 stylelint 或者 eslint-plugin-tailwindcss,能检查一些基本问题,但检查不了“设计质量”这种主观性更强的东西。
“impeccable”这个方向之所以有意思,是因为它试图把这三类思路整合起来,并且通过 CLI 和 browser extension 两个入口,让 AI 在生成代码的当下就能获得设计约束,而不是等到代码写完再去检查。
3. impeccable 的核心设计思路拆解
3.1 把设计系统变成机器可读的约束
impeccable 的第一个核心思路是:设计系统不应该是给人看的文档,而应该是给机器读的约束。具体来说,就是把你的间距基数、颜色 token、圆角规范、阴影层级、字体阶梯、断点设置这些东西,从 Figma 或者设计文档里抽出来,变成一份结构化的配置文件。
这份配置文件大概长这样:
{ "spacing": { "base": 4, "scale": [0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64] }, "colors": { "primary": { "50": "#eff6ff", "500": "#3b82f6", "900": "#1e3a8a" }, "neutral": { "50": "#fafafa", "500": "#737373", "900": "#171717" } }, "radius": { "sm": 4, "md": 8, "lg": 12, "full": 9999 }, "shadow": { "sm": "0 1px 2px rgba(0,0,0,0.05)", "md": "0 4px 6px rgba(0,0,0,0.1)", "lg": "0 10px 15px rgba(0,0,0,0.1)" }, "typography": { "scale": [12, 14, 16, 18, 20, 24, 30, 36, 48], "weights": [400, 500, 600, 700] }, "breakpoints": { "sm": 640, "md": 768, "lg": 1024, "xl": 1280 } }这份配置的作用是:当 AI 生成代码时,它不再是从无限的可能性里瞎猜,而是在一个有限的、经过设计的选项空间里做选择。间距只能是 scale 里的值,颜色只能是 colors 里定义的值,圆角只能是 radius 里定义的值。这就把“设计质量”从一个主观判断问题,转化成了一个约束满足问题。
3.2 CLI 作为约束注入的入口
为什么是 CLI?因为 CLI 是 AI coding agents 最自然的交互界面。你用 codex cli 也好,用其他命令行工具也好,本质上都是在终端里跟 AI 对话。impeccable 如果做成一个 CLI 工具,就可以在 AI 生成代码的流程中插入一个“约束注入”的步骤。
具体来说,这个 CLI 可以做几件事。第一,初始化项目时,扫描现有的代码库,提取出实际使用的间距、颜色、圆角等值,生成一份初始配置。第二,在 AI 生成代码之前,把配置转换成一段简短的 prompt 前缀,自动附加到用户的输入里。第三,在 AI 生成代码之后,对生成的代码做一次静态检查,标记出违反配置的地方。
我实测下来,第二步是最关键的。因为 AI 的上下文窗口是有限的,你不能把整份配置都塞进去。impeccable 的做法应该是只注入“当前任务相关”的约束。比如用户要生成一个卡片组件,那就只注入间距、圆角、阴影、颜色这几类约束,字体和断点可以暂时不注入。这样 prompt 前缀可以控制在 200 个 token 以内,对 AI 的注意力影响最小。
3.3 Browser extension 作为视觉验证的闭环
CLI 解决了“生成时约束”的问题,但解决不了“生成后验证”的问题。AI 生成的代码到底视觉上对不对,最终还是要看渲染结果。这就是 browser extension 的用武之地。
impeccable 的 browser extension 思路应该是:在浏览器里打开 AI 生成的页面,extension 自动扫描页面上的所有元素,检查它们的实际计算样式是否符合配置。比如检查所有 margin 和 padding 是否是 4 的倍数,检查所有文字颜色和背景色的对比度是否达到 WCAG AA 标准,检查所有可交互元素是否有 hover 和 focus 状态,检查响应式断点处布局是否正常。
这个验证结果可以反馈回 CLI,形成一个闭环。如果发现违规,CLI 可以自动生成一段修复 prompt,让 AI 重新生成有问题的部分。这就把“生成-验证-修复”的循环自动化了。
3.4 为什么这个组合是合理的
单独看 CLI 或者单独看 browser extension,都不足以解决“AI 前端设计质量”这个问题。CLI 的优势是离 AI 近,能在生成时施加影响;browser extension 的优势是离真实渲染近,能捕捉到静态分析捕捉不到的问题。两者结合,才能覆盖从“意图”到“实现”到“验证”的完整链路。
这个设计思路背后的逻辑是:不要试图让 AI 一次就生成完美的代码,而是建立一个快速反馈循环,让 AI 在循环中逐步逼近完美。这比单纯优化 prompt 或者单纯加强 lint 规则都要有效,因为它把问题拆解成了多个可独立优化的环节。
4. 落地实操:搭建一套前端质量约束流程
4.1 第一步:提取现有设计 token
如果你已经有一个成型的项目,第一步是从现有代码里提取设计 token。不要手动去整理,那样太慢而且容易遗漏。写一个脚本,扫描所有样式文件,统计出实际使用的间距值、颜色值、圆角值、字体大小,然后取出现频率最高的那些。
# 以 Tailwind 项目为例,提取所有使用过的 spacing 类 grep -rhoE '(p|m|gap|space-[xy])-\[?[0-9]+' src/ | \ grep -oE '[0-9]+' | sort -n | uniq -c | sort -rn这个命令会输出每个间距值的使用次数。你会发现,实际使用的间距值可能只有 8 到 10 个,而不是 Tailwind 默认的几十个。把这些值整理成你的 spacing scale,就得到了第一份约束。
颜色提取稍微复杂一点,因为颜色可能出现在 Tailwind 类里、CSS 变量里、或者内联样式里。我的做法是先用正则把所有十六进制颜色和 rgb 颜色抓出来,然后按色相和明度聚类,手动确认几个主要色板。
注意:提取阶段不要追求完美,先拿到 80% 的 token 就够了。剩下的 20% 可以在后续迭代中补充。追求一次性完美会让你卡在提取阶段出不来。
4.2 第二步:生成约束配置文件
把提取出来的 token 整理成一份 JSON 或者 YAML 配置文件。这份文件要放在项目根目录下,方便 CLI 读取。配置文件的格式要尽量简单,不要搞太多嵌套层级,因为后续要把它转换成 prompt 前缀,太复杂的结构转换起来麻烦。
我建议的配置结构是扁平的:
spacing: [0, 4, 8, 12, 16, 24, 32, 48, 64] colors: primary: "#3b82f6" primary-hover: "#2563eb" text: "#171717" text-muted: "#737373" bg: "#ffffff" bg-subtle: "#fafafa" border: "#e5e5e5" radius: [0, 4, 8, 12, 9999] shadow: sm: "0 1px 2px rgba(0,0,0,0.05)" md: "0 4px 6px rgba(0,0,0,0.1)" font-size: [12, 14, 16, 18, 20, 24, 30, 36] font-weight: [400, 500, 600, 700]这份配置大概 30 行,转换成 prompt 前缀大概 150 个 token,完全在可接受范围内。
4.3 第三步:编写 CLI 注入脚本
CLI 脚本的核心逻辑是:读取配置文件,根据当前任务类型筛选相关约束,生成 prompt 前缀,然后调用 AI 编码工具。
import yaml import subprocess import sys def load_config(path="impeccable.yaml"): with open(path) as f: return yaml.safe_load(f) def build_prefix(config, task_type): lines = ["请严格遵守以下设计约束:"] if task_type in ["component", "page"]: lines.append(f"间距只能使用:{config['spacing']}") lines.append(f"圆角只能使用:{config['radius']}") lines.append(f"颜色只能使用:{config['colors']}") if task_type == "component": lines.append(f"阴影只能使用:{list(config['shadow'].keys())}") if task_type in ["page", "layout"]: lines.append(f"字体大小只能使用:{config['font-size']}") return "\n".join(lines) def main(): task_type = sys.argv[1] # component / page / layout user_prompt = sys.argv[2] config = load_config() prefix = build_prefix(config, task_type) full_prompt = f"{prefix}\n\n任务:{user_prompt}" # 调用你的 AI 编码工具,这里以 codex cli 为例 subprocess.run(["codex", "generate", full_prompt]) if __name__ == "__main__": main()这个脚本的用法是:
python impeccable.py component "生成一个用户头像卡片,包含头像、姓名、职位和关注按钮"脚本会自动把设计约束拼接到 prompt 前面,然后调用 AI 工具生成代码。
4.4 第四步:Browser extension 验证实现
Browser extension 的核心逻辑是:在页面加载完成后,遍历所有元素,检查计算样式是否符合配置。
// content script 核心逻辑 const config = await fetchConfig(); function checkSpacing(el) { const style = window.getComputedStyle(el); const values = [ style.marginTop, style.marginBottom, style.marginLeft, style.marginRight, style.paddingTop, style.paddingBottom, style.paddingLeft, style.paddingRight ]; return values.filter(v => { const num = parseFloat(v); return num > 0 && !config.spacing.includes(num); }); } function checkContrast(el) { const style = window.getComputedStyle(el); const fg = style.color; const bg = style.backgroundColor; if (bg === "rgba(0, 0, 0, 0)") return null; // 透明背景跳过 const ratio = calculateContrast(fg, bg); return ratio < 4.5 ? { fg, bg, ratio } : null; } // 遍历所有元素 document.querySelectorAll("*").forEach(el => { const spacingIssues = checkSpacing(el); const contrastIssue = checkContrast(el); if (spacingIssues.length || contrastIssue) { highlightElement(el, { spacingIssues, contrastIssue }); } });这个 extension 会在页面上用红色边框标出有问题的元素,鼠标悬停时显示具体问题。我实测下来,一个中等复杂度的页面大概能查出 20 到 50 个问题,其中大部分是间距不在 scale 里,少部分是颜色对比度不够。
4.5 第五步:形成修复循环
发现问题不是目的,修复才是。Browser extension 可以把问题列表导出成 JSON,CLI 脚本读取这个 JSON,生成修复 prompt,再调用 AI 重新生成有问题的部分。
def build_fix_prompt(issues): lines = ["以下元素存在设计规范问题,请修复:"] for issue in issues: lines.append(f"- 元素 {issue['selector']}:{issue['description']}") lines.append("修复时请严格遵守设计约束。") return "\n".join(lines)这个循环跑几轮之后,AI 生成的前端代码质量会有明显提升。我的经验是,第一轮能解决 70% 的问题,第二轮能解决 90%,第三轮基本就干净了。
5. 常见问题与排查技巧实录
5.1 AI 不遵守约束怎么办
这是最常见的问题。你明明在 prompt 里写了“间距只能使用 4 的倍数”,AI 还是生成了p-3或者p-5。原因通常是约束在 prompt 里的位置太靠后,被 AI 的注意力机制忽略了。
解决办法是把约束放在 prompt 的最前面,并且用明确的格式标记出来。比如用[约束]开头,用[/约束]结尾,让 AI 知道这是一段需要特别关注的内容。另外,约束条目不要超过 10 条,太多了 AI 记不住。如果约束确实很多,就按任务类型分批注入。
还有一个技巧是:在约束后面加一句“违反约束的代码将被拒绝”,给 AI 一个“惩罚信号”。实测下来,这句话能提升大概 20% 的遵守率。
5.2 提取的 token 太碎怎么办
有时候提取出来的间距值有 20 多个,颜色有 30 多个,这时候约束就失去了意义,因为选项太多了。解决办法是做一次聚类合并。间距值相差 2px 以内的合并成一个,颜色值用感知哈希做聚类,把相近的颜色归为一组。
我一般会把间距值控制在 8 到 12 个,颜色控制在 10 到 15 个,圆角控制在 4 到 5 个。这个数量级既能覆盖大部分场景,又不会让 AI 感到困惑。
5.3 Browser extension 误报太多怎么办
Browser extension 的误报主要来自第三方组件和浏览器默认样式。比如你引入了一个 UI 库,它的间距值不在你的 scale 里,extension 就会报错。解决办法是加一个白名单机制,把第三方组件的选择器前缀加入白名单,跳过检查。
另外,浏览器默认样式也会导致误报,比如body的默认 margin 是 8px,不在你的 scale 里。这个可以在 extension 初始化时先把body、html这些根元素排除掉。
5.4 性能问题怎么处理
遍历所有元素并计算样式是一个比较重的操作,在大型页面上可能会导致卡顿。我的做法是只检查“可见且可交互”的元素,用IntersectionObserver做懒检查,只检查进入视口的元素。另外,检查结果可以缓存起来,同一个元素在样式没变的情况下不重复检查。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| AI 不遵守间距约束 | 约束位置太靠后 | 检查 prompt 结构 | 约束前置,加惩罚语句 |
| 提取的 token 太多 | 未做聚类合并 | 统计 token 频率 | 按频率和相似度合并 |
| Extension 误报多 | 第三方组件干扰 | 查看报错元素选择器 | 加白名单跳过 |
| 页面检查卡顿 | 遍历元素太多 | 用 Performance 面板分析 | 懒检查 + 缓存 |
| 修复循环不收敛 | 约束之间有冲突 | 检查约束配置 | 消除冲突约束 |
| 颜色对比度总是不达标 | 品牌色本身对比度低 | 计算对比度值 | 调整色板或加文字阴影 |
提示:修复循环不要超过 5 轮,超过之后收益递减,而且可能陷入死循环。如果 5 轮还没修好,说明约束配置本身有问题,需要回头调整配置。
6. 我在实操中总结的几条经验
第一,约束要少而精。我一开始把能想到的约束都写进去了,结果 AI 的遵守率反而下降了。后来精简到 8 条核心约束,遵守率明显提升。人的注意力有限,AI 也是。
第二,验证要自动化,但修复要半自动。完全自动的修复循环容易跑偏,AI 可能会为了满足约束而牺牲功能。我的做法是让 extension 自动发现问题,但修复 prompt 生成后由我确认一下再执行。
第三,设计 token 要定期更新。项目在演进,设计系统也在变。我每个月会跑一次 token 提取脚本,看看有没有新的间距值或颜色值出现,及时更新配置。
第四,不要追求 100% 的约束遵守率。有些场景确实需要打破约束,比如特殊的营销页面或者品牌活动页。这时候可以在配置里加一个exceptions字段,允许特定文件或特定组件跳过检查。
第五,Browser extension 的检查结果要可视化。光看 JSON 报告很难定位问题,在页面上直接高亮有问题的元素,效率会高很多。我用的方案是给问题元素加一个红色虚线边框,鼠标悬停显示问题详情。
这套流程跑顺之后,我用 AI 生成前端代码的效率大概提升了 40%,返工率下降了 60%。当然,这只是一个起点。前端设计的“无可挑剔”是一个很高的标准,AI 目前还达不到,但通过合理的约束和验证机制,可以让它离这个标准更近一步。