1. 从“impeccable”这个词说起:一个被低估的前端设计标准
第一次看到“impeccable”作为项目标题,我脑子里蹦出来的不是词典释义,而是一个很具体的画面:一个前端页面,从间距到对齐,从颜色到动效,每一处都挑不出毛病,但你又说不上来它到底“设计”了什么。这种状态,就是 impeccable——无懈可击,但不是靠堆料堆出来的。
这个词最近频繁出现在 AI coding agents、frontend design、CLI、browser extension 这几个热搜词的交叉地带,不是偶然。它背后指向的是一个很实际的问题:当 AI 开始大量参与前端代码生成,我们怎么保证产出的东西不是“能跑就行”,而是真正达到可交付、可维护、经得起 review 的水准?
我做了十多年前端,带过团队,也踩过无数“看起来没问题、上线后全是问题”的坑。这篇文章想聊的,就是怎么把 impeccable 这个标准,拆成一套可执行、可复现的工程实践。不管你是刚接触 AI coding agents 的新手,还是已经在用 CLI 工具链做自动化流程的老手,都能从里面找到能直接抄作业的东西。
核心关键词会自然分布在后面各个章节里:AI coding agents 怎么介入设计流程、frontend design 的验收标准怎么定、CLI 工具链怎么串起来、browser extension 在调试和验证环节扮演什么角色。我不打算写成工具说明书,而是按一个真实项目的推进节奏来展开——从思路拆解,到细节落地,再到问题排查。
2. 整体设计思路:为什么“无懈可击”比“惊艳”更难做
2.1 先搞清楚 impeccable 到底在要求什么
很多人把 impeccable 理解成“完美”,这其实偏了。完美是一个终点,impeccable 更像是一种状态描述:没有明显缺陷,没有低级错误,没有让人皱眉的细节。它不追求第一眼的惊艳,而是追求经得起反复看、反复用。
放到 frontend design 的语境里,这意味着几件事:
- 视觉一致性:间距、字号、圆角、阴影,这些基础 token 在整个项目里必须统一。我见过太多项目,首页按钮圆角 8px,内页变成 6px,用户说不出来哪里怪,但就是觉得不专业。
- 交互可预期:hover、focus、active、disabled 这些状态必须齐全,而且行为一致。AI coding agents 生成代码时最容易漏的就是 focus 态和 disabled 态,因为它训练数据里这两类样本相对少。
- 边界情况覆盖:超长文本、空数据、加载失败、网络慢,这些场景不处理,页面在真实环境里就会“破相”。
- 可维护性:代码结构清晰,命名有意义,样式不散落。这一条最容易被忽略,但它决定了三个月后你还敢不敢改这个页面。
我个人的判断标准很简单:把页面截图发给一个不做前端的朋友,问他“有没有哪里看着别扭”,如果他说不出来,但整体感觉舒服,那基本就摸到 impeccable 的边了。
2.2 为什么选择 CLI + browser extension 这条路线
现在做前端设计验证,路子很多。有人纯靠肉眼,有人用设计稿比对工具,有人写一堆 E2E 测试。我最终倾向 CLI 加 browser extension 的组合,理由有三条。
第一,CLI 适合做批量、可重复的检查。比如用命令行工具跑一遍所有页面的对比度检测、间距检测、响应式断点检测,这些活儿人眼做一遍要半天,CLI 几分钟出结果。热搜词里 codex cli、openspec cli、minimax cli 这些工具,本质上都是在解决“把重复劳动交给命令行”这个问题。
第二,browser extension 适合做实时、上下文相关的验证。你在浏览器里打开页面,扩展直接告诉你当前元素的对比度是多少、间距是否符合 token、focus 态有没有丢。这种即时反馈是 CLI 给不了的,因为 CLI 看不到你当前的操作上下文。
第三,两者结合能形成闭环。CLI 负责“广撒网”,把明显问题筛出来;browser extension 负责“精定位”,在开发过程中实时拦截。我实测下来,这套组合能把视觉回归问题的发现时间从“上线后”提前到“提交前”,省下来的返工成本非常可观。
注意:工具选型不要贪多。我见过团队同时上四五种检查工具,结果规则冲突、报告打架,最后没人看。选一套主力的,把规则调准,比堆工具重要得多。
2.3 AI coding agents 在这套流程里的正确位置
AI coding agents 现在很火,但很多人用错了地方。让它从零生成一个完整页面,出来的东西往往“能看但不能用”——结构乱、样式散、边界情况全漏。我的做法是把它放在“执行层”,而不是“决策层”。
具体来说,设计规范、token 体系、组件结构这些决策,人来定。定好之后,让 AI coding agents 去填充具体实现,比如根据给定的 token 生成对应的 CSS 变量、根据组件规范生成基础结构、根据检查规则生成测试用例。这样它的产出有约束、有边界,质量可控。
热搜词里提到的 zcode cli、trae cli 这类工具,我理解它们的价值也在这里:不是替代人做设计决策,而是把决策之后的重复劳动自动化。你把规则喂给它,它帮你跑,跑完你验收。这个分工想清楚了,AI 才真的能提效,而不是制造更多返工。
3. 核心细节解析:把 impeccable 拆成可检查的项
3.1 视觉 token 体系:一切一致性的地基
要让页面达到 impeccable,第一步不是写样式,是定 token。token 就是一套命名好的设计变量,比如--space-sm、--color-primary、--radius-md。所有样式都引用 token,不写魔法数字。
为什么这一步这么关键?因为一致性问题的根源,往往是同一个视觉值在不同地方被写成了不同的数字。你今天写margin: 16px,明天写margin: 1rem,后天写margin: 15px,三个月后没人知道哪个是对的。token 体系就是把这个口子堵死。
我常用的 token 分层是这样的:
| 层级 | 作用 | 示例 |
|---|---|---|
| 基础层 | 原始值,不带语义 | --blue-500: #3b82f6 |
| 语义层 | 带用途含义 | --color-primary: var(--blue-500) |
| 组件层 | 特定组件专用 | --button-bg: var(--color-primary) |
基础层和语义层分离的好处是,换主题时只改语义层的映射,基础层不动。组件层则是给特殊组件留的口子,但要注意控制数量,组件层 token 太多,说明你的设计系统开始失控了。
间距体系我一般用 4px 基准,也就是 4、8、12、16、24、32、48、64 这样递进。为什么是 4 不是 5 或 8?因为 4 能被大多数屏幕密度整除,缩放时不容易出现半像素模糊。这个细节很多人不注意,但在高分屏上,半像素会导致文字和边框发虚。
实操心得:token 命名不要用
--color-1、--color-2这种,过两周你自己都忘了 1 和 2 的区别。用语义命名,比如--color-danger、--color-success,一眼就知道用途。
3.2 状态完整性:AI 最容易漏的那一块
前面提过,AI coding agents 生成代码时,hover 态通常有,focus 态和 disabled 态经常漏。这不是它笨,是训练数据里这两类样本占比低。所以验收时,状态检查必须单独列一项。
一个交互元素,完整状态至少包括:
- default:默认态
- hover:鼠标悬停
- focus:键盘聚焦,必须有可见的 focus ring
- active:按下瞬间
- disabled:禁用态,要降低对比度但不能低到看不清
- loading:如果涉及异步操作
focus 态尤其重要,因为它关系到键盘用户能不能正常操作。我见过太多项目,鼠标用着没问题,一按 Tab 键就找不到焦点在哪。这在无障碍标准里是硬伤,在实际使用里也是实打实的体验问题。
focus ring 的设计有个常见误区:直接用浏览器默认的蓝色 outline。能用,但和你的设计体系不搭。我的做法是自定义 focus ring,用outline加outline-offset,颜色取主色的深色版本,宽度 2px,offset 2px。这样既明显又不突兀。
3.3 响应式断点:不是越多越好
响应式设计里,断点数量是个容易走极端的地方。新手喜欢设一堆断点,320、375、414、768、1024、1280、1440、1920,结果维护起来要命。老手往往只设两三个,但覆盖得刚刚好。
我的经验是,断点应该由内容决定,不是由设备决定。具体做法:把浏览器窗口从宽到窄慢慢拖,当布局开始“别扭”的时候,记下那个宽度,那就是一个断点。通常一个中等复杂度的项目,3 到 4 个断点就够了。
断点命名也别用设备名,比如--mobile、--tablet,因为设备尺寸一直在变。用--bp-sm、--bp-md、--bp-lg这种,或者直接用数值--bp-640、--bp-1024,更直观。
3.4 边界情况清单:上线前必须过一遍
边界情况是 impeccable 和“差不多”之间的分水岭。我整理了一份必查清单,每次上线前过一遍:
- 超长文本:标题超过 50 个字会怎样?用户名超过 20 个字符会怎样?
- 空数据:列表为空时显示什么?搜索无结果时显示什么?
- 加载中:有没有 loading 态?骨架屏还是转圈?
- 加载失败:网络错误时有没有提示?能不能重试?
- 图片缺失:图片加载失败时有没有占位?
- 极端数值:金额是 0 或负数时怎么显示?进度是 0% 或 100% 时怎么显示?
- 快速操作:连续点击按钮会不会重复提交?
这份清单看着琐碎,但每一条都是真实项目里踩过的坑。我印象最深的一次,是一个金额显示组件,正常数据都没问题,结果遇到一个 0 元的订单,显示成了空白,用户以为页面坏了。这种问题,只有边界清单能兜住。
4. 实操过程:从零搭一套可复现的检查流程
4.1 环境准备与工具安装
先说环境。我假设你已经有一个前端项目,Node.js 环境正常。下面这套流程不依赖特定框架,React、Vue、原生都适用。
第一步,装 CLI 检查工具。以样式检查为例,我常用 stylelint 做 CSS 规范检查,用 pa11y 做无障碍检查。安装命令:
npm install --save-dev stylelint stylelint-config-standard pa11y第二步,配置 stylelint。在项目根目录建.stylelintrc.json:
{ "extends": "stylelint-config-standard", "rules": { "color-no-invalid-hex": true, "declaration-block-no-duplicate-properties": true, "custom-property-pattern": "^[a-z][a-z0-9-]*$", "selector-class-pattern": "^[a-z][a-z0-9-]*$" } }这里custom-property-pattern是强制 token 命名规范的,selector-class-pattern是强制类名规范的。规则不用一次上太多,先上最关键的几条,跑顺了再加。
第三步,装 browser extension。Chrome 商店里搜“accessibility insights”或者“axe devtools”,这两个我都用过,axe 的规则库更全,accessibility insights 的引导更好。装完之后,在开发者工具里会多一个面板,点一下就能扫当前页面。
注意:browser extension 的扫描结果要结合上下文看。它报的有些问题是误报,比如装饰性图片没有 alt 属性,这其实是合理的。不要为了清零报告而改代码,要理解每条规则背后的意图。
4.2 用 CLI 跑批量检查
环境好了,接下来把检查串成命令。在package.json的 scripts 里加:
{ "scripts": { "lint:css": "stylelint \"src/**/*.css\"", "lint:a11y": "pa11y --standard WCAG2AA http://localhost:3000", "check:all": "npm run lint:css && npm run lint:a11y" } }跑npm run check:all,stylelint 会扫所有 CSS 文件,pa11y 会打开本地服务扫无障碍。pa11y 需要本地服务先起来,所以顺序上先npm run dev,再跑检查。
pa11y 的输出是文本报告,问题多了看着累。可以加--reporter json输出 JSON,再用脚本解析成表格。我一般会写个小脚本,把问题按严重程度排序,critical 和 serious 的优先处理,minor 的排期处理。
这套流程跑顺之后,可以接到 CI 里。每次提交代码自动跑一遍,有问题直接拦住。这一步的价值在于,它把“检查”从“靠自觉”变成了“靠机制”。人总会偷懒,机制不会。
4.3 用 browser extension 做实时验证
CLI 是批量检查,browser extension 是实时检查。开发过程中,我习惯开着 axe devtools 面板,改完一段样式就扫一下。它的好处是即时反馈,你刚写完的代码,问题立刻暴露,改起来成本最低。
具体操作:打开页面,F12 打开开发者工具,切到 axe 面板,点“Scan all of my page”。扫描完会列出问题,每条问题点开能看到具体元素和修复建议。
我常用的几个检查项:
- 对比度:文字和背景的对比度是否达到 4.5:1(正文)或 3:1(大字号)
- 焦点顺序:Tab 键遍历顺序是否和视觉顺序一致
- ARIA 属性:自定义组件的 role 和 aria-label 是否正确
- 表单标签:每个输入框是否有关联的 label
对比度这一项,我建议单独用工具算。axe 报的对比度是基于当前渲染颜色的,如果颜色是动态计算的,它可能算不准。手动算的话,用 WebAIM 的对比度检查器,输入前景色和背景色,直接出结果。
4.4 把检查结果转成修复任务
检查跑完,报告一堆问题,怎么修?我的做法是按“影响面 × 修复成本”排优先级。
| 优先级 | 判断标准 | 处理方式 |
|---|---|---|
| P0 | 影响核心流程,如按钮点不了 | 立即修 |
| P1 | 影响体验但不阻断,如对比度不足 | 当次迭代修 |
| P2 | 细节问题,如间距不统一 | 排期修 |
| P3 | 优化项,如动效可以更顺 | 有空再修 |
P0 和 P1 必须当次解决,P2 可以攒一批一起改,P3 看情况。这个分级不是为了偷懒,是为了把有限的精力花在刀刃上。我见过团队追求“零问题报告”,结果把大量时间花在 P3 上,核心体验反而没打磨好。
实操心得:修复问题时,一次只改一类。比如这一轮专门修对比度,下一轮专门修焦点态。混着改容易漏,也容易引入新问题。
5. 常见问题与排查技巧实录
5.1 对比度检查总是不通过怎么办
对比度是最常见的问题,也是最容易解决的。核心原则:正文文字对比度至少 4.5:1,大字号(18px 以上或 14px 加粗)至少 3:1。
如果对比度不够,有三个方向调:
- 加深文字颜色
- 减淡背景颜色
- 加大字号或字重
我一般优先调文字颜色,因为背景色往往涉及品牌色,不好动。文字颜色加深时,注意不要直接调到纯黑,纯黑在浅色背景上对比度是够了,但看着生硬。用深灰,比如#1f2937,对比度够,观感也柔和。
有个坑要注意:半透明文字。比如color: rgba(0,0,0,0.6),它的实际对比度取决于背景色。如果背景是白色,实际颜色是#666,对比度约 5.7:1,够用。但如果背景是浅灰,实际颜色会更浅,可能就不够了。所以半透明文字一定要在真实背景上验证。
5.2 focus 态丢失的几种典型场景
focus 态丢失,通常有这几个原因:
第一,全局重置了 outline。很多 CSS reset 里有一句*:focus { outline: none },这一句直接把所有 focus 态干掉了。如果你用了这类 reset,必须补上自定义 focus 样式。
第二,用了div或span做按钮。这些元素默认不可聚焦,自然没有 focus 态。解决方法是加tabindex="0"和role="button",但更好的做法是直接用button元素。
第三,overflow: hidden裁掉了 focus ring。如果父容器有overflow: hidden,focus ring 超出容器部分会被裁掉。解决方法是给 focus ring 留出空间,或者用outline-offset负值让它往里收。
排查方法很简单:打开页面,按 Tab 键,看焦点能不能正常移动,焦点在哪儿。如果焦点“消失”了,就是上面某一种情况。
5.3 AI 生成代码的样式散落问题
用 AI coding agents 生成代码,最常见的问题是样式散落。它可能在这个组件里写内联样式,在那个组件里写 CSS 文件,在另一个组件里用 CSS-in-JS,风格完全不统一。
我的应对方法是:生成之前先给约束。在 prompt 里明确说“所有样式使用 CSS 变量,变量定义在tokens.css里,组件样式写在同名的.module.css文件里”。约束给得越具体,产出越可控。
生成之后,用 stylelint 扫一遍,把不符合规范的挑出来。如果散落问题严重,不要一个个改,直接让 AI 按规范重写一遍,比手工改快。
5.4 响应式断点处的布局跳动
布局跳动通常发生在断点切换的瞬间。原因往往是断点两侧的布局差异太大,或者有元素在断点处突然显示/隐藏。
解决方法有两个方向:
第一,让断点两侧的布局渐变,而不是突变。比如从三列变两列,不要直接display: none掉一列,而是让列宽平滑过渡。
第二,检查有没有元素在断点处改变尺寸。比如图片在窄屏变小,如果没设固定宽高比,加载时会跳动。给图片设aspect-ratio能解决大部分这类问题。
排查时,把浏览器窗口慢慢拖动,盯着看哪里跳。跳的地方就是问题所在。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方向 |
|---|---|---|---|
| 对比度不通过 | 文字太浅或背景太深 | 用对比度工具算实际值 | 调文字色或背景色 |
| focus 态消失 | outline 被重置 | 按 Tab 看焦点 | 补自定义 focus 样式 |
| 样式散落 | 无统一规范 | stylelint 扫描 | 定规范后重写 |
| 布局跳动 | 断点处突变 | 拖动窗口观察 | 平滑过渡或设宽高比 |
| 空数据白屏 | 没处理空态 | 造空数据测试 | 加空态占位 |
| 重复提交 | 没做防抖 | 快速连点测试 | 加 loading 或防抖 |
这张表我贴在工位上,遇到问题先查表,大部分情况能直接定位。
6. 工具链的取舍:CLI 和 browser extension 怎么配合最顺手
6.1 CLI 适合什么,不适合什么
CLI 的优势是批量、可重复、可接入自动化。适合做的事:全量样式检查、无障碍扫描、构建产物分析、依赖体积检查。这些活儿的特点是规则明确、结果确定、不需要人判断。
CLI 不适合做的事:需要上下文判断的检查。比如“这个间距看着别扭”,CLI 判断不了,因为它不知道设计意图。再比如“这个动效太快了”,CLI 也判断不了,因为快慢是主观的。
所以 CLI 的定位是“守门员”,把明确的规则问题拦住,把需要判断的问题留给人。
6.2 browser extension 的不可替代性
browser extension 的优势是实时、上下文相关、可视化。你在开发过程中,改一行代码,扫一下,立刻知道有没有引入问题。这种即时反馈是 CLI 给不了的,因为 CLI 要跑完整流程。
另外,browser extension 能看到运行时状态。比如一个组件在特定交互后才出现,CLI 静态扫描扫不到,但 browser extension 能在它出现时扫。这个能力对于检查动态内容特别有用。
我常用的组合是:开发时开着 browser extension,随时扫;提交前跑一遍 CLI,确保没有遗漏;CI 里再跑一遍 CLI,作为最后一道防线。三层防护,基本能兜住绝大多数问题。
6.3 工具配置的几条经验
第一,规则不要一次全开。stylelint 有几百条规则,全开的话报告能刷屏。先开最关键的十几条,跑顺了再逐步加。
第二,规则要团队统一。每个人的编辑器配置不一样,有人用 Prettier,有人不用,格式会打架。解决办法是把配置写进项目里,用.editorconfig和.stylelintrc统一,编辑器自动读取。
第三,报告要能看懂。CLI 的默认输出有时候太啰嗦,可以配置成简洁模式,只显示文件名、行号、问题描述。browser extension 的报告要按严重程度排序,先看 critical。
第四,定期回顾规则。项目在变,规则也要跟着变。每季度花半小时看看哪些规则从来没触发过,可能是规则太松;哪些规则天天触发,可能是规则太严或者代码确实有问题。
7. 把 impeccable 变成团队习惯
7.1 从个人实践到团队规范
一个人做到 impeccable 不难,难的是让整个团队都做到。我的经验是,靠自觉没用,靠机制才行。
具体做法:把检查接入 CI,提交代码自动跑,不通过不让合并。这一步是硬约束,保证底线。然后在 code review 清单里加上视觉检查项,比如“focus 态是否完整”“边界情况是否处理”。这一步是软约束,提升上限。
硬约束保证不出大问题,软约束推动持续改进。两者结合,团队的整体水准会慢慢上来。
7.2 新人怎么快速上手这套标准
新人上手,最怕的是一堆规则不知道从哪看起。我的做法是给一份“最小检查清单”,只有五条:
- 所有颜色用 token,不写死值
- 所有交互元素有 focus 态
- 所有列表处理空数据
- 所有图片有 alt 或占位
- 所有按钮防重复提交
这五条覆盖了 80% 的常见问题,新人先做到这五条,再逐步扩展。等这五条成了肌肉记忆,再加更细的规则。
7.3 持续维护的节奏
impeccable 不是一次性的活儿,是持续的状态。我的节奏是:每次迭代开始前,跑一遍全量检查,把历史问题清一清;迭代过程中,开发时实时检查;迭代结束前,再跑一遍全量检查,确保没有新增问题。
这个节奏看着简单,但坚持下来不容易。我的办法是把它写进迭代流程文档里,作为固定环节。流程一旦固定,就不容易漏。
最后分享一个我自己的小习惯:每次上线前,我会把核心页面在手机、平板、桌面各打开一遍,用眼睛过一遍。工具能查规则问题,但查不了“感觉”。有时候工具全绿,但看着就是不对劲,这时候相信眼睛,别信报告。这个习惯帮我拦下过好几次“工具查不出但用户能感觉到”的问题。