1. 从“impeccable”说起:一个被低估的前端质量命题
第一次看到“impeccable”这个词被拿来命名一个前端项目,我的反应是:这名字起得挺狂。impeccable,无瑕的、无可挑剔的。在前端圈子里混久了的人都知道,前端界面要做到“无可挑剔”有多难——不是功能跑通就完事了,而是像素级对齐、交互零延迟、响应式断点不穿帮、暗色模式不刺眼、无障碍标签一个不漏。这些事单拎出来都不算难,难的是每一处都做到位,而且是在持续迭代中保持住。
这个项目本质上是一套围绕AI coding agents构建的前端设计质量保障工具链。它同时提供了CLI和browser extension两种形态,核心目标是让 AI 辅助编码产出的前端界面,从“能跑”提升到“impeccable”的水准。说白了,就是给那些用 AI 写前端代码的人,配一个随时在线的设计质量审查官。
为什么这件事值得单独做一个项目?因为现在用 AI coding agents 写前端的人越来越多,但大家普遍遇到一个尴尬:AI 生成的代码逻辑上没问题,样式上却经常“差一口气”。按钮的 padding 忽大忽小,卡片阴影在不同页面深浅不一,移动端断点处文字溢出,focus 状态被 outline: none 干掉了导致键盘用户没法用。这些问题人眼扫一遍未必能全发现,但用户用起来就是觉得“不精致”。impeccable 要解决的就是这个“最后一公里”的精致度问题。
适合谁来参考这篇内容?三类人。第一类是用 AI 工具写前端但总被设计稿打回的开发者;第二类是想把设计规范自动化的前端团队负责人;第三类是对 CLI 工具链和浏览器扩展开发感兴趣的工程师。不管你基础如何,下面我会把设计思路、核心实现、实操步骤和踩坑经验都摊开讲。
2. 整体设计思路:为什么是 CLI 加浏览器扩展的双形态
2.1 单形态方案的局限在哪里
做前端质量检查这件事,市面上已有不少方案。纯 CLI 的 lint 工具能查代码层面的问题,比如 stylelint 查 CSS 规范、eslint 查 JS 逻辑,但它们看不到渲染后的真实效果。一个margin: 0 auto在代码里完全合规,渲染出来可能因为父容器宽度问题根本没居中。纯浏览器扩展呢,能看到渲染结果,但没法接入 CI 流程,每次都得人工点开看,规模化很难。
impeccable 选择双形态,逻辑很清晰:CLI 负责可自动化、可进 CI 的部分,浏览器扩展负责需要真实渲染上下文的部分。两者共享同一套规则引擎和配置体系,保证检查标准一致。这个设计决策背后有个关键判断——前端质量检查不能只有一种触发时机。开发时在浏览器里实时看,提交前在终端里跑一遍,合并前在 CI 里卡一道,三个时机对应三种形态需求。
我试过只做浏览器扩展的方案,结果是团队里没人主动去点。也试过只做 CLI 的方案,结果是样式渲染问题全漏。双形态不是贪多,是被现实逼出来的。
2.2 规则引擎的抽象层设计
整个项目最核心的抽象是规则引擎。每条检查规则被定义为一个独立模块,包含四个部分:规则元信息(id、描述、严重级别)、匹配条件(针对哪些元素或代码模式生效)、检查逻辑(具体的判断函数)、修复建议(可选的自动修复方案)。
这种设计的好处是规则可以热插拔。CLI 和浏览器扩展都只是规则引擎的“宿主”,前者把 DOM 序列化后喂给引擎,后者直接在真实 DOM 上跑。规则本身不关心自己跑在什么环境里,只关心拿到输入、产出结果。这个抽象层做对了,后面加新规则、加新宿主都很轻松。
提示:如果你要复现类似架构,规则引擎的输入输出格式一定要尽早定死。我见过太多项目因为规则返回结构不统一,导致 CLI 和扩展两边解析逻辑各写一套,维护成本翻倍。
2.3 与 AI coding agents 的协作定位
这个项目没有试图取代 AI coding agents,而是定位成它们的“质检下游”。AI 负责生成,impeccable 负责审查。这个分工很重要。现在很多工具想一口气把生成和审查都做了,结果两头都不精。impeccable 的聪明之处在于,它假设代码已经由 AI 或人生成了,它只做一件事:找出不够 impeccable 的地方,并给出可操作的修复方向。
它甚至可以把检查结果反向喂回给 AI agent,让 agent 根据具体问题去修。这就形成了一个闭环:生成、检查、修复、再检查。对于用 codex cli 这类工具做前端开发的人来说,这个闭环能显著减少人工返工的次数。
3. 核心细节解析:规则体系与检查维度
3.1 视觉一致性检查的实现要点
视觉一致性是 impeccable 最基础也最常用的检查维度。它主要盯三件事:间距体系、颜色体系、字体体系。
间距检查的逻辑不是简单看 padding 值是否在某个范围,而是检查同一页面内相似元素的间距是否一致。比如所有卡片的内部 padding 应该相同,所有区块之间的垂直间距应该遵循同一套比例。实现上,它会先对页面元素做聚类,把结构相似的归为一组,然后检查组内间距值的方差。方差超过阈值就报警。
颜色检查更微妙一些。它会提取页面所有颜色值,检查是否都来自预定义的设计 token 集合。如果出现一个不在 token 里的十六进制色值,就会标记为“游离色”。这个检查能有效防止 AI 生成代码时随手写一个#3a7bd5这种没进设计系统的颜色。
字体检查关注字号阶梯和字重使用。一个常见问题是 AI 会生成font-size: 15px这种不在阶梯上的值,而设计系统里可能只有 14px 和 16px。impeccable 会把这些“阶梯外字号”揪出来。
3.2 交互状态覆盖检查
前端界面最容易出问题的地方是各种交互状态。默认状态好看,hover 状态没定义,focus 状态被干掉,disabled 状态和正常状态分不清。impeccable 对每个可交互元素检查四类状态:hover、focus、active、disabled。
focus 状态检查尤其重要。很多 AI 生成的代码会带outline: none来“美化”界面,但没提供替代的 focus 视觉反馈,这直接导致键盘用户无法使用。impeccable 会检测所有可聚焦元素,确认它们有可见的 focus 指示。这个检查在无障碍合规越来越被重视的今天,价值很高。
active 状态检查则关注点击反馈。按钮按下时如果没有视觉变化,用户会怀疑点击是否生效。impeccable 会检查按钮类元素是否有 active 态的样式定义。
3.3 响应式断点穿帮检测
响应式是 AI 生成前端代码的重灾区。AI 往往能写出在某个特定宽度下好看的布局,但断点切换时各种穿帮。impeccable 的响应式检查会在多个预设宽度下渲染页面,对比各宽度下的布局表现。
具体检查项包括:文字是否溢出容器、元素是否重叠、横向滚动条是否意外出现、图片是否变形、导航是否在某个宽度下彻底消失。这些检查需要真实渲染环境,所以主要在浏览器扩展形态下执行。CLI 形态下则通过解析 CSS 媒体查询和容器查询来做静态推断,覆盖面稍窄但能进 CI。
3.4 无障碍基础项扫描
无障碍检查不是 impeccable 的主打,但作为基础项存在。它扫描的是最容易被忽略又最容易修的那几类问题:图片缺 alt、表单控件缺 label、颜色对比度不足、语义标签误用(比如用 div 当按钮)。
颜色对比度检查用的是 WCAG 标准算法,计算前景色和背景色的对比度比值,低于 4.5:1 的正文文字和低于 3:1 的大号文字会被标记。这个检查在暗色模式下尤其有用,因为 AI 生成暗色主题时经常把文字和背景搞得太接近。
4. 实操过程:从安装到跑通第一条规则
4.1 CLI 形态的安装与初始化
CLI 形态的安装走的是标准包管理流程。假设你已经有了 Node.js 环境,全局安装即可。安装完成后,在项目根目录执行初始化命令,它会引导你生成一份配置文件。
# 全局安装 npm install -g impeccable-cli # 在项目根目录初始化配置 impeccable init初始化过程会问你几个问题:项目类型(React/Vue/原生)、设计 token 来源(CSS 变量/Tailwind 配置/自定义 JSON)、检查严重级别阈值。回答完这些问题后,会在项目根目录生成impeccable.config.json文件。
配置文件的结构大致如下:
{ "projectType": "react", "tokenSource": { "type": "css-variables", "path": "./src/styles/tokens.css" }, "severityThreshold": "warning", "ignore": [ "node_modules/**", "**/*.test.*" ], "rules": { "spacing-consistency": "error", "color-token-compliance": "error", "focus-visible": "error", "responsive-overflow": "warning" } }这里有个实操心得:severityThreshold建议初期设成warning,先把所有问题都看到,别一上来就卡 error 导致 CI 全红。等团队把存量问题清理得差不多了,再逐步把关键规则提到 error 级别。
4.2 浏览器扩展的加载与使用
浏览器扩展形态适合开发阶段实时检查。加载方式走的是开发者模式手动加载。把项目仓库里的extension目录下载到本地,在浏览器扩展管理页面开启开发者模式,选择“加载已解压的扩展程序”,指向该目录即可。
加载成功后,浏览器工具栏会出现 impeccable 的图标。点击图标会弹出检查面板,面板里列出当前页面所有被标记的问题,按严重级别分组。点击某条问题,页面上对应元素会高亮,方便定位。
扩展的检查是实时触发的。页面 DOM 发生变化后,它会重新跑一遍规则,面板内容自动更新。这个实时性对开发阶段很有帮助,改完样式立刻能看到问题是否消除。
注意:扩展在检查大型页面时会有性能开销。如果页面元素超过五千个,建议在扩展设置里开启“按需检查”模式,只在手动点击时跑规则,避免页面卡顿。
4.3 在 CI 流程中接入 CLI 检查
CLI 形态最大的价值是能进 CI。在项目的 CI 配置里加一步执行impeccable check,它会把检查结果以退出码形式返回。有 error 级别问题就返回非零退出码,CI 流程中断。
# 在 CI 脚本中执行检查 impeccable check --format json --output impeccable-report.json # 检查退出码 if [ $? -ne 0 ]; then echo "发现 impeccable 检查未通过的问题" exit 1 fi--format json参数让输出变成结构化 JSON,方便后续解析。你可以把这个报告上传到 CI 的 artifact 里,也可以写脚本解析后发到团队通知渠道。
这里有个参数选择上的考量:CI 里跑检查时,建议加上--changed-only参数,只检查本次提交涉及的文件对应的页面。全量检查在大型项目里可能跑好几分钟,只查变更部分能把时间压到几十秒。当然,定期全量检查还是要做的,可以放在每日定时任务里。
4.4 与 AI coding agents 的联动配置
如果你用 codex cli 这类工具做前端开发,可以把 impeccable 的检查结果喂回去。具体做法是在 agent 的工作流里加一个后置步骤:agent 生成代码后,自动跑 impeccable check,把报告里的问题列表作为下一轮 prompt 的输入。
# 伪代码示意:agent 生成后自动检查并反馈 impeccable check --format json > /tmp/report.json # 解析报告,提取问题描述 # 将问题描述拼入下一轮 agent prompt这个联动不需要 impeccable 本身做什么特殊适配,它只要输出结构化的、可读的问题描述就够了。问题描述里包含元素定位信息、问题类型、修复建议,这些信息对 AI agent 来说足够明确,它能据此定位到代码位置并修改。
5. 常见问题与排查技巧实录
5.1 检查结果误报怎么处理
误报是任何静态检查工具都绕不开的问题。impeccable 的误报主要来自两类情况:一是设计上确实有意为之的例外,二是规则匹配逻辑过于宽泛。
处理误报的第一手段是行内忽略注释。在代码里对应位置加一行注释,告诉 impeccable 跳过这条规则:
/* impeccable-disable-next-line spacing-consistency */ .special-card { padding: 13px; }第二手段是配置文件里的 ignore 规则。如果某个目录或某类文件整体不需要检查,在impeccable.config.json的ignore数组里加上路径模式即可。
第三手段是调整规则参数。比如间距一致性检查的方差阈值默认是 2px,如果你的设计系统允许更大浮动,可以调高这个值。规则参数都在配置文件的ruleOptions字段里,每个规则有自己可调的参数。
我个人的经验是:误报率超过 15% 的规则,要么调参数,要么直接关掉。一个总在喊狼来了的工具,团队很快就会无视它的所有输出。
5.2 浏览器扩展不生效的排查路径
扩展加载后没反应,按这个顺序排查:
| 排查项 | 检查方法 | 常见原因 |
|---|---|---|
| 扩展是否启用 | 扩展管理页看开关状态 | 加载后忘记启用 |
| 当前页面是否在允许列表 | 扩展设置里看域名白名单 | 默认只检查 localhost |
| 页面是否有跨域 iframe | 看控制台是否有跨域报错 | 扩展无法注入跨域 iframe |
| 规则是否全部被忽略 | 看配置文件 ignore 字段 | 配置写错导致全忽略 |
| 扩展版本与 CLI 版本是否匹配 | 对比两边版本号 | 规则引擎版本不一致 |
最常见的原因是域名白名单。扩展默认只对 localhost 和 127.0.0.1 生效,如果你在测试环境域名下调试,需要手动把域名加进白名单。
5.3 大型项目检查性能优化
元素数量超过一万的页面,全量跑规则会明显卡顿。优化手段有几个:
第一,开启增量检查。扩展会记录上次检查的 DOM 快照,只对变化部分重跑规则。这个在设置里默认开启,但如果页面用了大量动态渲染,快照对比本身也有开销,可以视情况关掉。
第二,按规则分组执行。把规则分成“快速规则”和“重量规则”两组,快速规则每次 DOM 变化都跑,重量规则只在手动触发时跑。重量规则主要是那些需要计算布局几何信息的检查,比如响应式溢出检测。
第三,限制检查深度。对于超长列表,只检查视口内可见的元素,视口外的等滚动到了再检查。这个策略在扩展设置里叫“视口优先模式”。
5.4 与现有 lint 工具的规则冲突
项目里通常已经有 stylelint 或 eslint,impeccable 的部分规则可能和它们重叠。比如颜色值检查,stylelint 也有类似规则。冲突的处理原则是:代码层面的规范交给 stylelint,渲染层面的规范交给 impeccable。
具体来说,如果一个规则只看代码文本就能判断,放 stylelint;如果需要知道元素在页面上的实际渲染结果才能判断,放 impeccable。按这个原则划分,间距一致性、响应式溢出、focus 可见性这些归 impeccable,颜色值格式、属性顺序、单位规范这些归 stylelint。
两边都配的情况下,建议在 impeccable 配置里把和 stylelint 重叠的规则关掉,避免同一问题报两遍,干扰开发者判断。
6. 规则扩展与二次开发
6.1 自定义规则的编写模板
impeccable 的规则是插件化的,你可以写自己的规则。一条规则就是一个模块,导出特定结构的对象。下面是一个自定义规则的骨架:
module.exports = { id: 'custom-button-size', description: '按钮尺寸必须来自预定义集合', severity: 'warning', // 匹配条件:只对 button 和 [role=button] 生效 match: (element) => { return element.tagName === 'BUTTON' || element.getAttribute('role') === 'button'; }, // 检查逻辑:返回问题数组 check: (element, context) => { const allowedSizes = context.config.allowedButtonSizes || [32, 40, 48]; const height = element.getBoundingClientRect().height; if (!allowedSizes.includes(Math.round(height))) { return [{ message: `按钮高度 ${height}px 不在允许集合内`, element: element, suggestion: `调整为 ${allowedSizes.join('/')}px 之一` }]; } return []; } };把这个文件放到项目的impeccable-rules目录下,在配置文件里引用目录路径,impeccable 启动时会自动加载。
6.2 规则调试的实用技巧
写自定义规则时,调试是个麻烦事。我的做法是先写一个最小复现页面,只包含触发规则所需的最少元素,然后在这个页面上反复跑。impeccable 提供了--debug参数,开启后会在控制台打印每条规则的匹配元素数量和检查耗时,方便定位是匹配逻辑写错了还是检查逻辑写错了。
另一个技巧是利用浏览器扩展的“规则沙箱”功能。在扩展面板里有一个调试标签页,可以粘贴规则代码,实时对当前页面跑,看返回结果。这个比改文件、重载扩展、刷新页面的循环快得多。
6.3 规则集的版本管理与团队分发
团队多人协作时,规则集本身也需要版本管理。建议把自定义规则目录纳入 Git 仓库,和项目代码一起管理。配置文件的规则开关和参数也一起提交。这样每个人拉下代码后,跑 impeccable 得到的结果是一致的。
如果多个项目共用一套规则,可以把规则目录做成独立的 npm 包,各项目通过依赖引入。impeccable 支持从 node_modules 里加载规则,配置里写包名即可。规则包更新后,各项目升级依赖就能拿到新规则。
提示:规则包升级可能引入新的检查项,导致原本通过的 CI 突然失败。建议规则包遵循语义化版本,新增规则走 minor 版本,修改现有规则行为走 major 版本,让各项目能控制升级节奏。
7. 我踩过的几个坑和对应解法
第一个坑是规则引擎的 DOM 序列化格式。CLI 形态下需要把页面 DOM 序列化后传给规则引擎,最初我用的是简化版序列化,只保留标签名和关键属性,结果很多依赖完整属性信息的规则跑不了。后来改成保留完整属性集,但过滤掉事件监听器这类不可序列化的内容,才解决问题。如果你要复现,序列化格式一定要覆盖规则可能用到的所有属性。
第二个坑是浏览器扩展的注入时机。扩展在document_idle时注入,但很多 SPA 页面在这个时机还没渲染完,导致检查的是空页面。解法是监听 DOM 变化,等页面稳定后再跑首次检查。判断稳定的方式是 MutationObserver 在 500ms 内没有收到新变化。
第三个坑是颜色对比度检查在渐变背景上的表现。WCAG 算法假设背景是纯色,遇到渐变背景时计算结果不准。我的处理是取渐变背景上元素所在位置的实际像素颜色作为背景色,这需要读取渲染后的像素,在扩展形态下用 canvas 截图取色实现。CLI 形态下则跳过渐变背景的对比度检查,标记为“需人工确认”。
第四个坑是 CI 环境下的字体渲染差异。CI 服务器上装的字体和开发者机器不同,导致文字宽度计算有偏差,响应式溢出检查在 CI 里报的问题在本地复现不了。解法是在 CI 环境里统一安装一套标准字体,并在 impeccable 配置里指定字体渲染的基准环境。
这几个坑的共同点是:它们都不是规则逻辑本身的问题,而是运行环境差异导致的。做这类工具,环境一致性比规则正确性更难保证。我的建议是尽早把 CI 环境和本地环境的差异摸清楚,能统一的统一,不能统一的就在配置里显式声明环境假设。
最后分享一个使用上的小技巧:impeccable 的检查报告支持--group-by参数,可以按元素类型、按规则、按严重级别分组输出。日常开发时我习惯按元素类型分组,这样能一次性看到某个组件所有的问题;做质量复盘时按规则分组,能看出哪类问题最普遍。这个参数用好了,同一份报告能服务不同的使用场景。