1. 从impeccable这个词说起一个被低估的前端质量信号第一次看到impeccable作为项目名我下意识去翻了它的词源——拉丁语impeccabilis意思是不会犯错的、无可挑剔的。放在前端设计语境里这个词其实非常精准地戳中了一个长期被忽视的痛点AI coding agents 生成的前端代码功能上往往能跑通但视觉和交互层面经常差一口气。这个差一口气具体差在哪我总结下来通常是三类问题。第一类是间距系统崩坏AI 生成的组件里 padding 和 margin 经常是 13px、17px、22px 这种随手写的数值完全没有 4px 或 8px 的栅格节奏页面看起来就是哪里不对劲但说不上来。第二类是状态覆盖不全hover、focus、active、disabled、loading、empty 这些状态里AI 通常只写 hoverfocus-visible 的轮廓线要么没有要么丑得离谱键盘用户直接没法用。第三类是响应式断点拍脑袋在 768px 和 1024px 之间经常出现布局塌陷因为 AI 只按它见过的常见断点写没考虑内容本身的换行临界点。impeccable这个项目要解决的就是让 AI coding agents 在生成前端代码时能有一套可校验、可复现的质量标准而不是靠人肉 review 去抓这些细节。它同时提供了CLI和browser extension两种形态这个组合本身就很有意思——CLI 负责在代码生成阶段做静态约束browser extension 负责在渲染阶段做动态校验一个管写的时候一个管跑起来之后。如果你正在用 Codex CLI、Claude Code、Cursor 这类工具做前端开发或者你在团队里负责前端代码规范落地这个项目的思路值得仔细拆一拆。它不是一个又一个 lint 工具而是把设计系统的约束前移到了 AI 生成环节。下面我会从它解决的问题、CLI 和扩展的分工、实际接入方式、以及我在类似方案上踩过的坑几个角度展开。2. AI 生成前端代码的最后一公里问题到底出在哪2.1 功能正确不等于视觉正确一个真实对比我拿同一个需求分别让两个 AI agent 生成过——做一个带搜索的卡片列表支持空状态和加载状态。功能层面两者都能跑但视觉层面差距肉眼可见。Agent A 生成的代码里卡片间距是gap: 16px卡片内边距是padding: 20px标题字号 18px正文字号 14px行高 1.5。看起来没问题对吧但实际渲染出来卡片之间的视觉密度偏高因为 16px 的 gap 配上 20px 的 padding卡片边界感很弱整片区域糊在一起。Agent B 生成的代码里间距是gap: 24pxpadding: 24px标题 20px/1.4正文 14px/1.6。这个组合的呼吸感明显更好因为 24px 的 gap 和 padding 形成了统一的节奏标题和正文的行高比例也更符合阅读习惯。问题在于Agent A 的代码没有任何错误。lint 能过类型能过测试能过。但设计 review 就是过不了。这就是最后一公里——从能跑到能看之间的那段路目前主要靠人肉把关。2.2 为什么现有的 lint 体系抓不住这些问题你可能会说那用 stylelint 加一套 design token 规则不就行了我试过效果有限原因有三个。第一lint 只能校验用了什么值不能校验值之间的关系。stylelint 可以禁止你写padding: 13px强制你用 token但它没法判断gap: 16px配padding: 20px这个组合在视觉上是否协调。这种组合层面的和谐度是 lint 的盲区。第二AI 生成代码的上下文是动态的。传统 lint 面对的是人写的代码模式相对稳定。但 AI 每次生成的代码风格可能都不一样今天用 Tailwind 的space-y-4明天用 CSS Modules 的margin-bottom: 1rem后天直接内联 style。lint 规则很难覆盖这种发散性。第三状态覆盖的完整性没法静态校验。一个按钮组件有没有 focus-visible 样式lint 可以检查是否存在:focus-visible选择器但没法检查这个 focus 样式在深色背景下是否可见。这需要实际渲染才能判断。2.3 impeccable的切入角度把校验拆成静态和动态两层这个项目的聪明之处在于它没有试图用一个工具解决所有问题而是明确划分了职责边界。CLI 层负责在代码生成后、提交前做静态校验。它检查的是那些可以脱离渲染环境判断的规则间距是否落在栅格上、颜色是否来自 token、字号是否在预设的 scale 里、交互元素是否声明了必要的状态选择器。这一层的输出是给开发者看的可以在 CI 里跑也可以作为 pre-commit hook。Browser extension 层负责在页面渲染后做动态校验。它检查的是那些必须看到实际效果才能判断的规则对比度是否达标、focus 轮廓是否可见、响应式断点处是否有溢出、空状态和加载状态是否真的被渲染出来了。这一层的输出是给设计 review 用的可以直接在浏览器里标注问题元素。这个分工的逻辑很清晰静态能抓的绝不放到动态动态才能抓的绝不硬塞给静态。我在自己团队落地类似方案时最大的教训就是一开始想把所有规则都塞进 lint结果规则越写越多误报率飙升最后没人看报告了。3. CLI 与 Browser Extension 的分工逻辑为什么不是二选一3.1 CLI 的适用场景与能力边界CLI 形态最适合嵌入到 AI coding agent 的工作流里。比如你用 Codex CLI 生成了一批组件代码在git commit之前跑一次impeccable check它会把所有违反设计约束的地方列出来并且给出具体的修复建议。我实测下来CLI 层最有价值的检查项是这三类间距栅格校验检查所有padding、margin、gap的值是否落在 4px 的倍数上或者你自定义的栅格单位。这个规则看起来简单但能抓出大量随手写的数值。颜色 token 校验检查是否使用了硬编码的 hex 值而不是设计系统里的 token。AI 特别喜欢写#3b82f6这种值因为它训练数据里见太多了。交互状态声明校验检查button、a、input这类交互元素是否声明了:hover、:focus-visible、:disabled状态。注意这里只检查是否声明不检查声明得好不好。CLI 的能力边界也很明确它看不到渲染结果所以对比度、溢出、实际布局效果这些它管不了。不要试图让 CLI 去判断视觉问题那是扩展的活。3.2 Browser Extension 补位的那部分能力Browser extension 的定位是设计 review 的自动化助手。你在浏览器里打开页面点一下扩展图标它会在页面上叠加一层标注把有问题的元素高亮出来。它最实用的几个检查项检查项判断依据为什么 CLI 做不了文字对比度实际计算前景色与背景色的对比度比值需要知道最终生效的背景色可能来自多层叠加Focus 可见性模拟 Tab 键聚焦检查轮廓是否可见需要实际渲染和交互响应式溢出在多个视口宽度下检查scrollWidth clientWidth需要真实布局计算空/加载状态检查是否存在对应的 DOM 节点或可触发的状态需要运行时状态这个分工带来的一个实际好处是CLI 可以在 CI 里跑扩展只能在本地跑但两者的规则集是共享的。也就是说你在扩展里发现的问题可以反向补充到 CLI 的规则里让下次生成时就能避免。3.3 两者共享的规则引擎设计从项目结构推测impeccable应该有一个共享的规则定义层CLI 和扩展各自实现规则的执行器。这种设计的好处是规则只写一遍但执行环境可以不同。我在自己项目里复现过类似架构核心是把规则定义成声明式的结构比如// 规则定义示例基于常见实践推测 { id: spacing-grid, severity: warning, appliesTo: [css, inline-style], check: (value, context) { const gridUnit context.config.gridUnit || 4; return value % gridUnit 0; }, message: (value, context) 间距值 ${value}px 不在 ${context.config.gridUnit}px 栅格上 }CLI 拿到这个规则后解析 CSS 文件里的所有间距属性逐个调用check。扩展拿到同一个规则后遍历渲染后的元素读取 computed style 里的间距值调用同一个check。规则逻辑完全复用只是数据来源不同。这个设计的关键在于规则的check函数必须是纯函数不能依赖任何环境特定的 API。一旦规则里出现了document或fs这种环境耦合的东西就没法共享了。4. 把 impeccable 接入现有工作流的几种姿势4.1 作为 AI coding agent 的后置钩子最自然的接入方式是在 AI agent 生成代码之后、你 review 之前自动跑一次 CLI 检查。以 Codex CLI 为例你可以在它的配置里加一个 post-generation hook或者更简单一点在package.json里加一个 script{ scripts: { check:design: impeccable check --path src/components --format compact } }然后在你常用的 git hook 里调用它。我自己的习惯是在pre-commit里跑但只对改动过的文件跑避免全量扫描太慢。# .husky/pre-commit基于常见实践 npx lint-staged npx impeccable check --staged --format compact这里有个坑要注意CLI 的退出码设计。如果所有 warning 都返回非零退出码那 pre-commit 会被频繁阻断团队很快就会把这个 hook 关掉。合理的做法是 error 级别返回非零warning 级别只输出不阻断。我在配置时会把间距栅格、颜色 token 这类设为 error把状态声明完整性设为 warning。4.2 在浏览器里做设计验收Browser extension 的使用场景更偏向设计验收。具体流程是开发在本地起服务设计师打开页面点扩展图标扩展自动扫描并生成一份问题清单。这份清单的价值在于它把主观的感觉不对变成了客观的这条规则没过。设计师不用再说这个间距看着别扭而是可以直接说这三个卡片的间距不在栅格上分别是 14px、18px、22px。沟通成本大幅降低。我建议在扩展里加一个导出报告的功能把问题清单导出成 Markdown 或 JSON直接贴到 PR 评论里。这样设计 review 的结论就留痕了后续回溯也有依据。4.3 与现有 lint 体系的共存策略不要试图用 impeccable 替代 stylelint 或 eslint。它们的职责不同eslint管 JavaScript/TypeScript 的逻辑正确性stylelint管 CSS 的语法和基础规范impeccable管设计系统的约束和视觉质量三者是叠加关系不是替代关系。我在配置时的顺序是eslint 先跑最快stylelint 其次impeccable 最后最慢但最有价值。如果前两个挂了第三个就不用跑了节省时间。另外要注意规则冲突。比如 stylelint 可能有一条规则要求padding用简写而 impeccable 的栅格检查是按单个值判断的。这种情况下要么调整 impeccable 的解析逻辑去理解简写要么在 stylelint 里关掉冲突的规则。我倾向于后者因为 impeccable 的检查更贴近设计意图。5. 实测中暴露的问题与我的应对方案5.1 误报率是这类工具的生命线我拿一个中等规模的项目约 80 个组件跑了一遍第一版规则集的误报率大概在 15% 左右。这个数字听起来不高但意味着每 7 个报警里就有 1 个是假的开发者很快就会失去信任。误报主要来自三个地方。第一是第三方组件的样式比如你引入了一个 UI 库它的间距值不遵循你的栅格但你不应该去改它。解决方案是加白名单机制按路径或按选择器前缀排除。第二是动态计算的值比如padding: calc(var(--base) * 1.5)静态解析拿不到最终值。解决方案是遇到calc、var这类表达式时跳过检查或者只检查表达式里的字面量部分。第三是设计上确实需要破格的地方比如某些装饰性元素故意用非栅格值。解决方案是支持行内注释豁免类似/* impeccable-disable-next-line */。5.2 性能全量扫描 vs 增量扫描CLI 全量扫描一个 80 组件的项目第一次跑花了大概 12 秒。这个时间在 CI 里可以接受但在 pre-commit 里就太慢了。我的优化方案是两层第一层是文件级增量只扫描 git staged 的文件。这一下就把时间降到了 1-2 秒。第二层是规则级增量把规则按快和慢分类快的规则如间距检查每次都跑慢的规则如跨文件的一致性检查只在 CI 里跑。Browser extension 那边性能问题更明显因为要遍历渲染后的 DOM。我的做法是只扫描视口内可见的元素滚动时懒加载扫描。另外把对比度计算这种重操作放到 Web Worker 里避免阻塞主线程。5.3 规则的可配置性设计一个硬编码的规则集是没法落地的因为每个团队的设计系统都不一样。impeccable 需要支持配置文件让团队能自定义栅格单位、颜色 token 列表、字号 scale 等。我建议的配置结构是这样的# .impeccablerc基于常见实践推测 grid: unit: 4 allowed: [0, 4, 8, 12, 16, 24, 32, 48, 64] colors: tokens: - --color-primary - --color-text - --color-bg allowHardcoded: false typography: scale: [12, 14, 16, 20, 24, 32, 48] lineHeight: min: 1.4 max: 1.8 states: required: [hover, focus-visible, disabled] interactiveSelectors: [button, a, input, select, textarea]这个配置的好处是它本身就是一份设计系统的文档。新加入的开发者看一眼这个文件就知道项目的间距节奏、颜色体系、字号层级是什么。6. 从 impeccable 延伸出的前端质量工程思考6.1 设计约束的左移是必然趋势传统流程里设计约束的校验发生在最后——设计 review 阶段。这时候改动的成本最高因为代码已经写完可能还联调过了。impeccable 这类工具的价值是把校验点前移到代码生成阶段和提交阶段。这个左移思路在测试领域已经验证过了单元测试左移到开发阶段在设计领域同样适用。越早发现的问题修复成本越低。一个间距问题在生成时发现改一行配置就行在设计 review 时发现要改代码、重新构建、重新验收在上线后发现可能还要发 hotfix。我预测接下来会有更多工具沿着这个方向做不只是间距和颜色还包括动效曲线、图标尺寸、阴影层级这些更细的设计维度。6.2 AI agent 需要可验证的约束才能稳定输出跟 AI coding agent 打交道多了会发现一个规律你给它越明确的约束它的输出越稳定。如果你只说做一个好看的卡片它每次给你的都不一样但如果你说间距用 4px 栅格、颜色用这三个 token、必须包含 hover 和 focus-visible 状态它的输出质量会稳定很多。impeccable 的 CLI 实际上就是在给 AI agent 提供这种可验证的约束。当 agent 知道它的输出会被这套规则检查时它生成代码时就会倾向于遵守这些规则。这比在 prompt 里写一堆要求要可靠得多因为 prompt 是软约束CLI 检查是硬约束。6.3 团队落地这类工具的三个前提根据我的经验这类工具要在团队里真正落地需要三个前提。第一设计系统本身要足够明确。如果你们团队连间距用 4px 还是 8px 栅格都没统一那工具跑出来的报告只会引发更多争论。工具是设计系统的执行者不是设计系统的制定者。第二要有一个人对规则集负责。规则不能只增不减否则误报会越积越多。我建议指定一个规则维护者定期 review 误报该关的规则关掉该调的阈值调掉。第三要接受渐进式合规。不要指望一上来就把所有历史代码都改合规。我的做法是只对新代码和改动过的代码强制检查历史代码慢慢迁移。这样团队不会因为突然多了几百个报错而抵触。7. 我在这类方案上踩过的坑与实操建议7.1 不要一开始就追求规则全覆盖我最初的想法是把所有设计规范都写成规则结果写了 40 多条跑出来的报告没人看。后来砍到 8 条核心规则反而大家都愿意看了。规则的价值不在于多而在于每一条都被认真对待。如果一条规则 90% 的情况都是误报那它就是在消耗团队的注意力。我现在的标准是一条规则如果误报率超过 10%就先下线等想清楚怎么降低误报再上。7.2 报告的可读性比规则的准确性更重要这个反直觉的结论是我踩坑踩出来的。早期我的报告输出是一堆 JSON开发者根本不想看。后来改成按文件分组、按严重程度排序、每条附带修复建议的格式使用率立刻上来了。一个可读的报告应该包含问题位置文件行号、问题描述人话不是规则 ID、修复建议具体怎么改、严重程度error/warning/info。这四样缺一不可。7.3 给 AI agent 的反馈要具体到改什么如果你用 impeccable 的检查结果去反馈给 AI agent 让它修复反馈信息一定要具体。不要说这个组件有设计问题而要说第 23 行的 padding 是 13px请改成 12px 或 16px保持 4px 栅格。我实测下来具体的反馈能让 AI 的修复成功率从 60% 提升到 90% 以上。模糊的反馈会让 AI 自由发挥结果往往引入新的问题。7.4 扩展的权限申请要克制Browser extension 如果申请了过多权限安装率会大幅下降。我建议只申请activeTab和scripting这两个必要权限不要申请all_urls这种宽泛权限。扫描逻辑只在用户主动点击扩展图标时触发不要做后台自动扫描。另外扩展的 UI 要轻量。我见过一些工具扩展点开后是一个全屏面板信息密度极低。好的做法是在页面右侧滑出一个窄面板问题列表紧凑排列点击某条问题就高亮对应元素。7.5 版本锁定与规则迁移设计系统是会演进的今天用 4px 栅格明天可能改成 8px。这时候规则集也要跟着迁移。我的建议是规则集要版本化配置文件里声明version: 2工具根据版本加载对应的规则集。这样老项目可以继续用老规则新项目用新规则迁移是渐进的而不是一刀切的。这个思路跟数据库 migration 很像——你不能指望所有代码同时升级但你可以让新旧规则共存逐步迁移。8. 写在最后一点个人体会我在前端质量这个方向上折腾了挺多年从最早的 eslint 自定义规则到后来的 stylelint 插件再到现在的 AI 生成代码校验一个越来越清晰的感受是工具能解决的问题前提是问题本身被定义清楚了。impeccable这个名字起得好因为它指向的是一个很高的标准——无可挑剔。但真正落地的时候你会发现无可挑剔不是一个终点而是一个持续逼近的过程。今天你觉得间距对齐了就无可挑剔了明天你会发现动效曲线还不够顺滑。标准在变工具也要跟着变。如果你打算在团队里推这类方案我的建议是从一条规则开始跑两周看误报率看使用率然后再决定加不加第二条。慢就是快这句话在质量工程里特别成立。急着上全套规则结果没人用还不如只上一条但大家都认真对待。另外别把这类工具当成AI 生成代码的补丁。它更像是设计系统的执行引擎。AI 只是让代码生成变快了但设计系统的约束一直都在只是以前靠人肉执行现在可以靠工具执行。想清楚这一点很多决策就顺了。