
1. 从impeccable说起一个被低估的前端设计关键词第一次看到impeccable这个词是在一个前端项目的 issue 讨论里。有人提了一句the spacing here is not impeccable当时我还愣了一下——这词不是无可挑剔的意思吗怎么被拿来形容界面了。后来才慢慢意识到在前端设计语境里impeccable 描述的是一种近乎苛刻的完成度间距、对齐、层级、动效节奏、边界状态每一处都经得起放大镜看。它不是一个功能而是一种标准。这两年 AI coding agents 大规模进入前端工作流情况变得有意思了。以前我们靠设计稿和肉眼去追求 impeccable现在 agent 能在几秒内生成一整套组件但生成出来的东西往往能用但不够好——间距是 16px 还是 24px 全凭它心情hover 态和 focus 态经常缺失暗色模式下颜色直接崩掉。于是impeccable从一个审美形容词变成了一个工程问题怎么让 AI 生成的前端代码达到无可挑剔的完成度这篇内容就是围绕这个核心问题展开的。我会拆解 impeccable 在前端设计里的具体含义讲清楚 AI coding agents 在这个环节的能力边界然后给出一套可复现的实操方案——包括 CLI 工具链的配置、browser extension 的辅助验证、以及一套我自己在用的完成度检查清单。适合正在用 AI 写前端、但总觉得产出差口气的开发者也适合想建立自己设计系统规范的技术负责人。不管你是刚接触 agent 的新手还是已经踩过一堆坑的老手下面这些内容应该都能直接拿去用。2. 拆解 impeccable前端设计里的无可挑剔到底指什么2.1 从视觉层到交互层的四重标准很多人把 impeccable 理解成好看这太浅了。我把它拆成四个层次每一层都有可量化的判断依据。第一层是视觉精度。间距系统是否统一比如全部基于 4px 或 8px 的倍数字号阶梯是否收敛一个页面里出现超过 6 种字号基本就失控了颜色是否有明确的语义 token而不是随手写 hex。这一层最容易被 AI 搞砸因为它生成代码时倾向于就近取值同一个卡片组件在不同文件里可能用了三套不同的 padding。第二层是状态完整性。一个按钮至少有 default、hover、active、focus、disabled、loading 六种状态。AI 生成的组件通常只给 default 和 hoverfocus 态直接缺失——这在无障碍层面是硬伤。impeccable 要求每个交互元素的状态机是闭合的没有漏网之鱼。第三层是响应式韧性。不是简单地加几个 media query而是在 320px 到 2560px 之间布局不塌、文字不溢出、图片不变形。我见过太多 AI 生成的栅格在 768px 附近直接错位因为 agent 只考虑了它训练数据里最常见的断点。第四层是动效节奏。过渡时长是否在 150ms 到 300ms 这个舒适区间缓动函数是否统一是否尊重prefers-reduced-motion。这一层最容易被忽略但恰恰是精致感的来源。提示判断一个界面是否 impeccable最快的办法是把它缩放到 200% 再看一遍。所有对齐问题、间距不一致、状态缺失都会在这一步暴露。2.2 为什么 AI 生成的代码天然达不到这个标准这里要说句公道话不是 agent 不行是任务定义本身有歧义。当你对 agent 说帮我做一个登录页它理解的目标是生成一个能跑的登录页而不是生成一个 impeccable 的登录页。这两个目标的差距就是完成度的差距。具体来说AI coding agents 有三个结构性短板。一是缺乏全局约束它不知道你项目里已经定义了--space-4: 16px这样的 token所以会自己造一套。二是倾向最小实现能少写一行就少写一行focus 态、aria 属性这些非必要代码经常被省略。三是没有视觉反馈闭环它写完代码看不到渲染结果自然无法自我修正。理解了这三点解决方案就清晰了我们要做的不是换一个更强的模型而是给 agent 补上约束、补上检查、补上反馈。这也是后面 CLI 工具链和 browser extension 要解决的核心问题。2.3 impeccable 与设计系统的关系单独追求 impeccable 是低效的因为它本质上是设计系统的执行结果。你有一套明确的设计 token、组件规范、状态定义impeccable 就是严格执行这套规范的自然产物。反过来如果没有设计系统每次都要靠人肉判断这个间距对不对那 AI 生成得越多你越累。我的做法是先把设计系统沉淀成机器可读的形式——CSS 变量、Tailwind config、或者一份 JSON token 文件——然后让 agent 在生成代码前先读这份文件。这一步的投入产出比极高后面会详细讲怎么落地。3. AI coding agents 在前端场景的能力边界3.1 agent 擅长什么不擅长什么用了大半年各种 agent 之后我总结出一条经验agent 擅长从零到一的结构搭建不擅长从一到一点五的精度打磨。让它生成一个包含表单、校验、提交逻辑的完整页面它做得又快又好结构清晰、命名规范。但让它把页面里所有间距统一到 8px 网格它反而容易出错——因为这类任务需要它同时持有全局视图和局部细节而这恰恰是当前 agent 的弱项。所以我的工作流是分段的结构搭建交给 agent精度打磨交给agent 检查工具的组合。检查工具负责发现问题agent 负责批量修复人负责最终验收。这个分工比让 agent 一把梭要可靠得多。3.2 上下文窗口与遗忘问题一个绕不开的现实是上下文窗口限制。当你让 agent 处理一个大型前端项目时它不可能同时看到所有文件。结果就是它在 A 文件里用了--color-primary在 B 文件里又写了个#3b82f6因为它忘了项目里有 token。应对办法有两个。一是把规范前置在每次对话开始时把设计 token 文件、组件规范摘要贴进去让它在有限的上下文里优先持有这些约束。二是分模块处理一次只让它改一个目录改完立刻验证避免跨模块的不一致。3.3 不同 agent 在前端任务上的表现差异我实测过几类主流 agent 在前端任务上的表现差异还挺明显的。纯代码补全类的工具适合写单个函数或组件但缺乏项目级视野对话式的 agent适合做重构和批量修改但需要你把约束讲清楚带浏览器能力的 agent能自己看渲染结果理论上最接近 impeccable但目前稳定性还参差不齐。选型建议是别指望一个 agent 包打天下。结构生成用一个批量重构用一个视觉验证用 browser extension 辅助。工具链的组合比单点工具的强弱更重要。4. CLI 工具链把 impeccable 变成可执行的检查4.1 为什么用 CLI 而不是纯靠 agent 对话CLI 的价值在于可重复、可脚本化、可进 CI。你跟 agent 对话说检查一下间距它每次检查的标准可能都不一样但你写一个 CLI 脚本它每次跑出来的结果是一致的。对于 impeccable 这种要求每次都一样好的标准确定性比智能更重要。而且 CLI 能进 pre-commit hook 和 CI pipeline这意味着完成度检查从事后人工 review变成了事前自动拦截。这个转变对团队协作的意义非常大——你不需要在 code review 里反复说这个间距不对工具已经帮你说了。4.2 搭建检查脚本的核心思路我的检查脚本分三类。第一类是静态检查扫描 CSS/SCSS/JSX 文件找出硬编码的颜色值、非网格倍数的间距、缺失的 focus 样式。第二类是结构检查验证组件是否包含所有必需的状态定义。第三类是视觉回归检查配合 browser extension 截图对比。静态检查用 Node 脚本就能写核心是正则匹配加白名单。比如找出所有padding: \dpx里不是 4 的倍数的值const fs require(fs); const path require(path); const GRID 4; const violations []; function checkFile(filePath) { const content fs.readFileSync(filePath, utf-8); const regex /(padding|margin|gap)\s*:\s*([^;]);/g; let match; while ((match regex.exec(content)) ! null) { const values match[2].match(/\dpx/g) || []; values.forEach(v { const num parseInt(v); if (num % GRID ! 0) { violations.push({ file: filePath, property: match[1], value: v, line: content.slice(0, match.index).split(\n).length }); } }); } } function walk(dir) { fs.readdirSync(dir).forEach(f { const full path.join(dir, f); if (fs.statSync(full).isDirectory()) { if (!full.includes(node_modules)) walk(full); } else if (/\.(css|scss|tsx|jsx)$/.test(f)) { checkFile(full); } }); } walk(./src); console.log(JSON.stringify(violations, null, 2));这个脚本跑一遍所有偏离网格的间距就无所遁形。你可以把它接到npm run lint:design里每次提交前自动跑。4.3 把检查结果喂回给 agent 自动修复光发现问题不够还得修。我的做法是把 CLI 输出的 JSON 直接喂给 agent让它按文件、按行号批量修复。prompt 大概是这样以下是一份设计规范违规清单请逐条修复。 规范要求所有间距必须是 4px 的倍数颜色必须使用 CSS 变量。 违规清单[粘贴 JSON] 修复时只改违规行不要动其他代码。实测下来这种检查-修复闭环能把修复准确率提到 90% 以上。剩下的 10% 通常是 agent 改错了上下文需要人工兜底。但相比纯人工效率提升是数量级的。注意喂给 agent 的违规清单不要一次超过 50 条否则它容易改着改着就忘了前面的约束。分批处理每批修完验证一次。4.4 常见 CLI 工具的选型与组合市面上前端相关的 CLI 工具很多我按用途分一下。代码质量类用 ESLint Stylelint前者管 JS/TS后者管 CSS两者都能自定义规则把设计规范写进去。格式化类用 Prettier统一代码风格减少无意义的 diff。视觉检查类目前没有特别成熟的 CLI主要靠 browser extension 配合。工具组合的原则是能用现成的就别自己写现成的不够用就写薄薄一层胶水。我上面那个网格检查脚本其实 Stylelint 也能实现但自定义脚本更灵活改起来快。选哪个取决于你的团队更熟悉哪套。5. Browser Extension给 agent 补上眼睛5.1 为什么 agent 需要视觉反馈前面说过agent 最大的短板是看不到渲染结果。它写完代码不知道这个按钮在暗色模式下是不是糊成一团不知道这个卡片在窄屏下是不是溢出了。browser extension 的价值就是把这个视觉反馈补上。具体来说extension 能做三件事截图把当前页面渲染结果抓下来测量读取元素的 computed style拿到真实的间距、颜色、字号对比把当前截图和基准截图做像素级 diff。这三件事组合起来就是一个自动化的视觉验收流程。5.2 用 extension 做设计走查的实操流程我的流程是这样的。第一步在基准版本上跑一遍 extension把所有关键元素的 computed style 导出成 JSON作为设计基线。第二步agent 改完代码后再跑一遍 extension导出新的 JSON。第三步diff 两份 JSON找出所有偏离基线的属性。这个流程的好处是客观。人眼看这个间距好像变了是不准的但 JSON diff 是精确的。而且 diff 结果可以直接喂给 agent让它针对性修复。// extension 里注入的采集脚本简化版 function collectStyles(selectors) { const result {}; selectors.forEach(sel { const el document.querySelector(sel); if (!el) return; const cs getComputedStyle(el); result[sel] { padding: cs.padding, margin: cs.margin, color: cs.color, background: cs.backgroundColor, fontSize: cs.fontSize, lineHeight: cs.lineHeight, borderRadius: cs.borderRadius }; }); return result; } // 采集关键元素 const baseline collectStyles([ .btn-primary, .card, .input-field, .nav-item ]); console.log(JSON.stringify(baseline, null, 2));把这段脚本通过 extension 注入到页面就能拿到真实渲染后的样式数据。这比读源码可靠得多因为源码里的值可能被继承、被覆盖、被媒体查询改写。5.3 状态覆盖的自动化验证状态验证是 extension 最被低估的用法。你可以写脚本自动触发 hover、focus、active然后采集每个状态下的样式检查是否都有明确定义。async function checkStates(selector) { const el document.querySelector(selector); const states {}; // default states.default getComputedStyle(el).backgroundColor; // hover通过 dispatchEvent 模拟 el.dispatchEvent(new MouseEvent(mouseover, { bubbles: true })); await new Promise(r setTimeout(r, 100)); states.hover getComputedStyle(el).backgroundColor; // focus el.focus(); await new Promise(r setTimeout(r, 100)); states.focus getComputedStyle(el).outline; return states; }跑完这个如果 hover 和 default 的颜色一样说明 hover 态没定义如果 focus 的 outline 是none说明无障碍有问题。这些结论直接、可执行比感觉不太对有用得多。5.4 extension 与 CLI 的协同单独用 extension 或单独用 CLI 都不够。CLI 管静态代码extension 管运行时表现两者结合才能覆盖完整链路。我的做法是CLI 在提交前跑拦截明显的规范违规extension 在部署后跑验证真实渲染效果。两道关卡各管一段。提示extension 采集的基线数据要版本化保存。每次设计系统更新基线也要同步更新否则 diff 会一直报假阳性。6. 一套可复现的 impeccable 工作流6.1 环境准备与工具安装先把基础环境搭起来。Node 18 是必须的因为很多现代 CLI 工具依赖它。然后装几个核心依赖npm init -y npm install --save-dev eslint stylelint stylelint-config-standard prettier npm install --save-dev typescript-eslint/parser typescript-eslint/eslint-pluginStylelint 的配置里把设计规范写进去。比如强制颜色使用变量、强制间距用网格{ extends: [stylelint-config-standard], rules: { declaration-property-value-allowed-list: { /^color$/: [/^var\\(--/, inherit, transparent], /^background(-color)?$/: [/^var\\(--/, transparent, none] }, declaration-property-value-disallowed-list: { /^(padding|margin|gap)/: [/\\dpx/] } } }最后一条规则会拦截所有用 px 写间距的地方逼你用var(--space-*)或者 rem。刚开始会有点烦但坚持一周代码一致性会有肉眼可见的提升。6.2 设计 token 的沉淀与同步设计 token 是整个工作流的地基。我建议用一份 JSON 作为单一数据源然后生成 CSS 变量和 JS 常量{ space: { 1: 4px, 2: 8px, 3: 12px, 4: 16px, 6: 24px, 8: 32px }, color: { primary: #3b82f6, primary-hover: #2563eb, text: #1f2937, text-muted: #6b7280 }, radius: { sm: 4px, md: 8px, lg: 12px } }写个脚本把它转成 CSS 变量const tokens require(./tokens.json); let css :root {\n; Object.entries(tokens.space).forEach(([k, v]) { css --space-${k}: ${v};\n; }); Object.entries(tokens.color).forEach(([k, v]) { css --color-${k}: ${v};\n; }); Object.entries(tokens.radius).forEach(([k, v]) { css --radius-${k}: ${v};\n; }); css }\n; require(fs).writeFileSync(./src/tokens.css, css);这份 tokens.css 就是 agent 生成代码时必须参考的字典。每次对话开始把它贴进上下文agent 的产出质量会明显不一样。6.3 agent 提示词的写法提示词的质量直接决定产出质量。我总结了一个模板分四段角色、约束、任务、验收标准。角色你是一名严格遵循设计系统的前端工程师。 约束 - 所有间距必须使用 var(--space-*) 变量 - 所有颜色必须使用 var(--color-*) 变量 - 每个交互元素必须包含 default/hover/focus/disabled 四种状态 - 过渡时长统一 200ms缓动函数 ease-out 任务实现一个卡片组件包含标题、描述、操作按钮。 验收标准 - 无硬编码颜色和间距 - focus 态有可见的 outline - 在 320px 宽度下不溢出这个模板的关键是验收标准要可验证。不要写看起来精致要写无硬编码颜色——后者 agent 能自查前者不能。6.4 完整流程演示假设要新增一个用户资料卡组件完整流程是这样的第一步把 tokens.css 和组件规范贴给 agent用上面的模板下任务。第二步agent 生成代码后跑npm run lint:design看有没有违规。第三步把违规清单喂回 agent 修复。第四步本地起服务用 extension 采集渲染样式和基线对比。第五步人工验收重点看 agent 和工具都没覆盖到的边界情况。这套流程跑顺之后一个新组件的完成度基本能稳定在接近 impeccable的水平。剩下的差距靠人工微调但工作量已经从从零打磨降到了最后收尾。7. 常见问题与排查技巧实录7.1 agent 反复改不对同一个问题怎么办这是最常见的坑。agent 改了三遍间距还是不对。原因通常是约束没进上下文或者约束之间有冲突。排查步骤先确认 tokens.css 在上下文里再检查是不是有两条规则互相矛盾比如一条要求用变量另一条又允许 px最后看是不是文件太大agent 只看到了局部。解决办法是缩小范围。别让它改整个文件只让它改那一个组件、那一个属性。范围越小准确率越高。7.2 视觉回归 diff 全是假阳性跑 diff 发现几百处差异仔细一看全是抗锯齿或者字体渲染的细微差别。这是像素级对比的通病。解决办法是设置容差阈值比如颜色差异小于 2% 就忽略位置偏移小于 1px 就忽略。另外截图前要固定字体加载、禁用动画减少随机因素。7.3 设计 token 更新后历史代码全报错这是好事说明检查生效了。但一次性修几百个文件不现实。我的做法是分批迁移按目录来每次迁移一个模块迁移完把该目录加入白名单。同时在新代码上强制检查老代码逐步跟进。别想着一步到位那只会让团队抵触。7.4 团队协作中的规范落地工具再好人不配合也白搭。我的经验是先让工具跑起来再谈规范。一开始别搞太严只拦截最明显的问题硬编码颜色让大家感受到工具帮我发现了问题。等大家习惯了再逐步加规则。一上来就全量强制只会被绕过。7.5 常见问题速查表问题现象可能原因排查方向解决手段agent 反复改不对约束未进上下文检查 prompt 是否含 tokens缩小修改范围分批处理diff 假阳性多容差阈值太严查看差异分布设置颜色/位置容差历史代码全报错规范更新未分批统计违规文件数按目录分批迁移focus 态缺失agent 省略非必要代码检查状态定义提示词强制要求四态暗色模式崩坏颜色硬编码搜索 hex 值强制使用语义 token响应式错位断点不完整测试 320/768/1024补充断点定义动效不统一缓动函数随意搜索 transition统一为 200ms ease-out注意这张表里的解决手段都是我自己踩坑后验证过的但不同项目情况不同建议先小范围试确认有效再推广。8. 我个人的一些实操体会最后聊几句掏心窝的话。追求 impeccable 这件事本质上是在跟差不多就行的本能对抗。AI 让生成代码变得太容易了容易到你很容易就接受能用就行的产出。但真正让产品有质感的恰恰是那些多花 20% 精力的细节——focus 态的那圈 outlinehover 时那 200ms 的过渡暗色模式下那个不刺眼的灰。我的建议是别把 impeccable 当成一次性任务当成一个持续运行的系统。CLI 检查进 CIextension 验证进部署流程设计 token 进版本控制。让追求完成度变成流水线的一部分而不是靠某个人的责任心。这样即使换了人、换了 agent产出的下限也能守住。还有一点工具是辅助判断力才是核心。agent 说改好了不代表真的好了工具说通过也不代表真的 impeccable。最终拍板的还是你的眼睛和手感。多看看那些让你觉得舒服的界面拆解它们为什么舒服这个能力比任何工具都值钱。