1. 为什么新手做出来的AI界面总有一股“AI味”
刚接触AI辅助前端开发的朋友,大概率都经历过这个阶段:让AI帮你生成一个登录页、一个数据看板、一个卡片列表,代码跑起来功能没问题,但盯着屏幕看三秒,心里就冒出一句——“这也太AI了吧”。
这个“AI味”到底从哪来?我拆过几十个新手用AI生成的页面,总结下来无非几个特征:清一色的紫色渐变按钮、圆角一律16px、阴影永远是0 4px 6px rgba(0,0,0,0.1)、字体不是Inter就是系统默认、间距全靠margin: 16px硬撑、配色要么灰得发闷要么艳得刺眼。更关键的是,这些页面之间毫无关联,做十个页面就是十套视觉语言,像十个不同的人各干各的。
问题的根子不在AI,在于你把AI当成了“代码生成器”,而不是“设计系统的执行者”。AI本身没有审美判断,它只会根据你的提示词去匹配训练数据里最高频的模式。你给的信息越模糊,它就越倾向于输出那个“最大公约数”——也就是最平庸、最安全、最没有个性的方案。而设计系统恰恰相反,它要求的是约束、是规则、是一致性。
所以这篇内容我想聊的不是“怎么让AI写出更炫的代码”,而是怎么把AI纳入一套设计系统的框架里,让它从“随机发挥的画师”变成“严格执行规范的实现者”。适合两类人看:一是刚入门前端、想用AI提效但被“AI味”困扰的新手;二是有点设计意识、但不知道怎么把设计规范落地到代码里的开发者。我会从设计令牌、组件约束、提示词工程、验收标准几个层面,把整套流程拆开讲清楚。
2. 先搞懂“设计系统”到底约束了什么
2.1 设计令牌:把“感觉”变成“数值”
很多人以为设计系统就是一套UI组件库,其实组件库只是最表层的产物。真正的地基是设计令牌(Design Token),也就是把颜色、间距、字号、圆角、阴影这些视觉决策,全部抽象成有名字的变量。
举个具体的例子。新手常犯的错是直接在CSS里写color: #7C3AED,下次想换个主色,得全局搜索替换,还容易漏。而设计令牌的做法是先定义:
:root { --color-primary-500: #7C3AED; --color-primary-600: #6D28D9; --color-neutral-50: #F9FAFB; --color-neutral-900: #111827; --space-1: 4px; --space-2: 8px; --space-4: 16px; --space-6: 24px; --radius-sm: 6px; --radius-md: 10px; --shadow-card: 0 1px 3px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.04); --font-size-sm: 13px; --font-size-base: 15px; --font-size-lg: 18px; }这套东西看起来简单,但它是对抗“AI味”的第一道防线。因为当你把这些令牌写进提示词里,AI就没有“自由发挥”的空间了——它必须用var(--color-primary-500)而不是自己编一个紫色,必须用var(--space-4)而不是随手写margin: 15px。
我实测下来,光是把颜色和间距令牌化,AI生成页面的“廉价感”就能降低一半以上。原因很直接:一致性本身就是高级感的来源。人类设计师做出来的界面之所以耐看,很大程度上是因为所有元素都遵循同一套节奏,而AI默认输出的是“每个元素各自为政”。
2.2 组件契约:规定“能改什么、不能改什么”
设计令牌解决的是“值”的问题,组件契约解决的是“结构”的问题。所谓组件契约,就是明确规定一个组件对外暴露哪些可配置项,哪些是内部实现细节不允许外部干预。
拿按钮举例。一个没有契约的AI生成按钮,可能长这样:
<button style={{background: '#7C3AED', color: '#fff', padding: '10px 20px', borderRadius: '8px'}}> 提交 </button>这种写法的问题在于,每个按钮都可以被随意改样式,改着改着整个项目就乱了。而有契约的按钮应该是:
<Button variant="primary" size="md" disabled={false}> 提交 </Button>variant只允许primary、secondary、ghost、danger四种,size只允许sm、md、lg三种。AI在生成代码时,只能在这几个枚举值里选,不能自己发明一个variant="purple-gradient"。
提示:组件契约最好用TypeScript的联合类型来强制约束,比如
type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger'。这样AI生成的代码如果越界,编译阶段就会报错,比运行时才发现问题要高效得多。
2.3 布局栅格:让间距有“数学依据”
“AI味”还有一个典型症状是间距混乱:这个卡片内边距20px,那个24px,标题和正文之间12px,正文和按钮之间18px。单看每个都还行,放一起就透着一种说不出的别扭。
解决办法是引入8pt栅格系统。所有间距必须是8的倍数(4px作为半档允许存在),这样任意两个元素之间的间距都有共同的公约数,视觉上自然就整齐了。我在提示词里会明确写:“所有margin、padding、gap必须使用var(--space-*)令牌,令牌值均为4的倍数,优先使用8的倍数。”
这条规则看起来死板,但实际效果非常明显。你可以做个对比实验:同一段提示词,一次不加栅格约束,一次加上,生成的两个页面并排看,后者会明显更“稳”。这不是玄学,是因为人眼对规律性格外敏感,而对随机性会本能地感到不适。
3. 把设计系统“喂”给AI的提示词写法
3.1 提示词的三层结构:角色、约束、示例
大部分人写提示词是这样的:“帮我写一个用户列表页面,要好看一点。”这种提示词得到的结果必然是AI味十足的,因为“好看”是个主观词,AI只能猜。
我习惯把提示词拆成三层:
第一层是角色设定,告诉AI它现在扮演什么角色。比如“你是一名严格遵循设计系统规范的前端工程师,你的任务是用给定的设计令牌和组件库实现页面,不允许自行发明任何颜色、间距或组件变体。”
第二层是硬约束,把设计令牌、组件契约、栅格规则全部列出来。这部分要写得像法律条文一样明确,不能有歧义。
第三层是示例,给一两个符合规范的代码片段作为参考。AI是极强的模式匹配器,你给它看什么,它就模仿什么。如果你给它看的是style={{...}}内联样式,它就会一直用内联样式;如果你给它看的是<Button variant="primary">,它就会照着这个模式走。
我实测下来,三层结构齐全的提示词,生成代码的可用率能从30%左右提升到80%以上。剩下的20%主要是业务逻辑层面的问题,视觉层面基本不需要大改。
3.2 用“负面清单”堵住AI的偷懒路径
除了正面告诉AI“要怎么做”,还得用负面清单告诉它“不许怎么做”。我常用的负面清单包括:
- 禁止使用内联
style属性,所有样式必须通过className或CSS变量 - 禁止使用
#开头的硬编码颜色值,必须引用var(--color-*) - 禁止使用非8倍数的间距值
- 禁止发明新的组件变体,只能用已定义的枚举值
- 禁止使用
!important - 禁止在组件内部写死宽度,必须使用弹性布局或栅格
这份清单不是拍脑袋想的,每一条都对应一个我踩过的坑。比如“禁止硬编码颜色”这条,是因为有一次AI生成了一个页面,主色用了#8B5CF6,而设计系统里定义的是#7C3AED,两个紫色肉眼几乎看不出差别,但放在一起就是不对劲,排查了半天才发现是AI自己编的色值。
注意:负面清单不要写太长,控制在10条以内。太长了AI会顾此失彼,反而容易在别的地方出错。优先把最影响一致性的几条放进去。
3.3 分步生成:先骨架、再填充、后微调
一次性让AI生成整个页面,是新手最容易犯的错。这样生成的代码往往结构混乱,改起来无从下手。我的做法是分三步:
第一步,只生成结构骨架。告诉AI“先用语义化标签搭出页面结构,不要写任何样式”。这一步的产出是类似这样的:
<main class="dashboard"> <header class="dashboard__header"> <h1>数据概览</h1> <Button variant="primary">导出</Button> </header> <section class="dashboard__stats"> <StatCard title="总用户" value="12,847" /> <StatCard title="活跃度" value="68%" /> <StatCard title="转化率" value="3.2%" /> </section> <section class="dashboard__chart"> <ChartPlaceholder /> </section> </main>第二步,逐块填充样式。针对每个区块单独发提示词,比如“给.dashboard__stats写样式,使用grid布局,三列等宽,gap用var(--space-6),小屏幕下变成单列”。
第三步,整体微调。把生成的所有代码拼起来,再让AI检查一遍一致性:“检查以下代码中是否有硬编码颜色、非8倍数间距、未使用设计令牌的地方,列出问题并修复。”
这三步走下来,虽然比一次性生成多花几分钟,但后期修改的时间能省下好几倍。而且分步生成还有个好处:每一步的产出你都能看懂、能控制,不会出现“AI写了一坨我看不懂的代码”这种情况。
4. 从零搭一个“抗AI味”的组件库骨架
4.1 目录结构与命名约定
在写任何组件之前,先把目录结构定下来。我推荐的结构是这样的:
src/ styles/ tokens.css # 设计令牌 reset.css # 基础重置 utilities.css # 工具类 components/ Button/ Button.tsx Button.module.css index.ts Card/ Input/ ... patterns/ # 组合模式,如登录表单、数据卡片组 pages/命名上有个小技巧:CSS类名用BEM风格,但只保留到Block和Element两层,不用Modifier。Modifier的职责交给组件的props来处理。比如.card__title可以,但.card__title--large就不要,改成通过<Card.Title size="lg">来控制。
这样做的好处是,AI在生成代码时,类名模式非常固定,不容易跑偏。你可以在提示词里直接写:“类名必须遵循block__element格式,不允许出现--修饰符,不允许出现驼峰或下划线。”
4.2 用CSS Modules隔离样式作用域
新手项目里样式冲突是高频问题。AI生成的代码尤其容易出这个问题,因为它不知道你项目里已经有哪些类名,很可能生成一个.title把之前的样式覆盖了。
CSS Modules能很好地解决这个问题。每个组件的样式文件独立,类名在编译时会自动加上哈希后缀,天然隔离。配合设计令牌使用,组件样式文件里只需要写结构相关的属性,颜色、间距、圆角全部引用令牌:
/* Button.module.css */ .button { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); border: none; border-radius: var(--radius-md); font-size: var(--font-size-base); font-weight: 500; cursor: pointer; transition: background-color 0.15s ease, opacity 0.15s ease; } .primary { background: var(--color-primary-500); color: #fff; } .primary:hover { background: var(--color-primary-600); } .secondary { background: var(--color-neutral-50); color: var(--color-neutral-900); border: 1px solid var(--color-neutral-200); } .sm { padding: var(--space-1) var(--space-3); font-size: var(--font-size-sm); } .md { padding: var(--space-2) var(--space-4); } .lg { padding: var(--space-3) var(--space-6); font-size: var(--font-size-lg); }注意这里padding用的是var(--space-*),字号用的是var(--font-size-*),没有任何硬编码数值。AI照着这个模式生成其他组件时,也会自然沿用这套写法。
4.3 组件Props的类型约束怎么写
TypeScript的类型系统是约束AI的利器。以Button为例:
type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger'; type ButtonSize = 'sm' | 'md' | 'lg'; interface ButtonProps { variant?: ButtonVariant; size?: ButtonSize; disabled?: boolean; loading?: boolean; children: React.ReactNode; onClick?: () => void; } export function Button({ variant = 'primary', size = 'md', disabled = false, loading = false, children, onClick, }: ButtonProps) { const cls = [ styles.button, styles[variant], styles[size], loading ? styles.loading : '', ].filter(Boolean).join(' '); return ( <button className={cls} disabled={disabled || loading} onClick={onClick}> {loading ? <Spinner size="sm" /> : children} </button> ); }这套类型定义写进提示词后,AI生成的调用代码基本不会越界。我试过故意在提示词里写“给我一个紫色的渐变按钮”,AI会回复“设计系统中没有紫色渐变变体,可用的variant为primary、secondary、ghost、danger,是否使用primary?”——这就是类型约束起作用的体现。
5. 实测中那些“AI味”反复出现的位置
5.1 阴影和圆角:AI最爱的两个“重灾区”
如果只能挑两个地方来治理AI味,我会选阴影和圆角。AI默认生成的阴影往往是0 4px 6px rgba(0,0,0,0.1)这种又大又散的,圆角则是清一色8px或12px。这两个值单独看没问题,但满屏都是同一个阴影和圆角,就会显得很“塑料”。
我的做法是在设计令牌里定义三档阴影和三档圆角,并规定使用场景:
| 令牌 | 值 | 使用场景 |
|---|---|---|
--shadow-sm | 0 1px 2px rgba(0,0,0,0.05) | 输入框、小按钮的默认态 |
--shadow-md | 0 1px 3px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.04) | 卡片、下拉菜单 |
--shadow-lg | 0 8px 24px rgba(0,0,0,0.12) | 模态框、悬浮面板 |
--radius-sm | 6px | 按钮、输入框、标签 |
--radius-md | 10px | 卡片、面板 |
--radius-lg | 16px | 模态框、大容器 |
关键是规定“什么场景用什么档”,而不是让AI自由选。比如提示词里写:“卡片统一使用var(--shadow-md)和var(--radius-md),按钮统一使用var(--shadow-sm)和var(--radius-sm),模态框统一使用var(--shadow-lg)和var(--radius-lg)。”这样生成出来的页面,层次感自然就出来了。
5.2 字体层级:别让AI自己“发明”字号
AI生成的字号经常是14px、15px、16px、18px、20px、24px混着来,毫无规律。解决办法是定义一套模数字号阶梯,比如1.25倍递增:
--font-size-xs: 12px; --font-size-sm: 13px; --font-size-base: 15px; --font-size-lg: 18px; --font-size-xl: 22px; --font-size-2xl: 28px; --font-size-3xl: 34px;然后在提示词里规定:“页面标题用--font-size-2xl,区块标题用--font-size-lg,正文用--font-size-base,辅助文字用--font-size-sm。”AI照着这个映射关系生成,字号就不会乱。
这里有个细节值得注意:行高也要令牌化。我一般定义--leading-tight: 1.25、--leading-normal: 1.5、--leading-relaxed: 1.75,标题用tight,正文用normal,长段落用relaxed。行高对阅读体验的影响比字号还大,但恰恰是AI最容易忽略的。
5.3 空状态和加载态:AI最容易糊弄的地方
新手用AI生成页面,往往只关注“有数据时长什么样”,忽略了空状态、加载态、错误态。而这三个状态恰恰是体现设计系统完整度的地方。
我的做法是在组件契约里强制要求每个数据展示组件都必须实现这四个状态:
interface DataViewProps<T> { data: T[] | null; loading: boolean; error: string | null; emptyText?: string; }然后在提示词里写:“任何展示列表或数据的组件,必须处理loading、error、empty、success四种状态,loading用骨架屏,empty用插画加文案,error用重试按钮。”这样AI就不会只给你一个“有数据”的版本了。
提示:骨架屏的样式也要纳入设计令牌,比如
--skeleton-bg: var(--color-neutral-100)、--skeleton-radius: var(--radius-sm),避免AI每次生成不同的骨架屏样式。
6. 验收环节:怎么判断AI生成的代码“合格”了
6.1 一份可执行的检查清单
代码生成完,别急着往项目里合。我习惯用一份检查清单过一遍,清单不长,但每一条都对应一个真实踩过的坑:
- 搜索代码中是否有
#开头的颜色值,有则不合格 - 搜索是否有
px结尾的间距值(除了1px边框),有则不合格 - 检查所有
border-radius是否引用了var(--radius-*) - 检查所有
box-shadow是否引用了var(--shadow-*) - 检查所有
font-size是否引用了var(--font-size-*) - 检查组件是否只使用了已定义的variant和size枚举值
- 检查是否有内联
style属性 - 检查空状态、加载态、错误态是否实现
这份清单可以写成脚本自动跑,也可以手动过。我一般用简单的grep命令就能筛出大部分问题:
# 查找硬编码颜色 grep -rn "#[0-9A-Fa-f]\{3,6\}" src/components --include="*.css" # 查找硬编码间距 grep -rn "padding: [0-9]" src/components --include="*.css" grep -rn "margin: [0-9]" src/components --include="*.css"跑一遍下来,如果还有硬编码值,就退回给AI让它修复。修复的提示词也很简单:“以下代码中存在硬编码值,请替换为对应的设计令牌,令牌定义见附件。”
6.2 视觉走查:用“并排对比法”找问题
代码层面的检查过了,还得做视觉走查。我的方法是把AI生成的页面和设计系统里已有的页面并排放在一起看。重点看三个东西:
一是节奏感。把页面缩小到50%看,如果间距忽大忽小、元素忽左忽右,说明栅格没对齐。正常的页面缩小后应该能看到清晰的纵向或横向对齐线。
二是层次感。眯着眼睛看,能不能一眼分出主标题、次标题、正文、辅助文字四个层级。如果眯眼后一片模糊分不出主次,说明字号和字重对比不够。
三是色彩克制度。数一下页面上出现了几种颜色。一个合格的页面,主色加中性色一般不超过5种。如果出现了七八种颜色,大概率是AI自己加戏了。
这套走查方法不需要什么设计功底,新手也能快速上手。我带的几个新人用这个方法,基本两三轮就能把AI味压下去。
6.3 把验收结果反哺回提示词
验收不是终点,而是下一轮生成的起点。每次验收发现的问题,都应该变成提示词里的新约束。比如发现AI总是把卡片间距写成20px,就在提示词里加一条“卡片间距必须使用var(--space-6)即24px”。发现AI生成的表格行高不一致,就加一条“表格行高统一使用var(--space-10)即40px”。
这样迭代几轮之后,你的提示词会越来越精准,AI生成代码的合格率也会越来越高。我自己的提示词模板从最初的一百多字,迭代到现在快两千字,但换来的是生成即用的体验,综合效率反而更高。
7. 从“能用”到“耐看”还差哪几步
7.1 给交互状态留出设计空间
AI生成的页面往往只考虑静态展示,hover、focus、active、disabled这些交互状态要么没有,要么很敷衍。而恰恰是这些细节,决定了页面是“能用”还是“耐看”。
我的做法是在设计令牌里为每个语义色定义完整的交互状态:
--color-primary-500: #7C3AED; /* 默认 */ --color-primary-600: #6D28D9; /* hover */ --color-primary-700: #5B21B6; /* active */ --color-primary-100: #EDE9FE; /* disabled背景 */ --color-primary-300: #C4B5FD; /* disabled文字 */然后在提示词里规定:“所有可交互元素必须定义hover、active、focus-visible、disabled四种状态,hover用深一档的颜色,active用深两档,focus-visible用2px outline加2px offset,disabled用浅色背景加浅色文字。”
这条规则加上之后,页面的“完成度”会明显提升。因为交互状态是用户能直接感知到的,有和没有的差别,比静态样式大得多。
7.2 动效要克制,但要有
AI生成的页面要么完全没动效,要么加一堆花哨的动画。我的原则是:动效只用在状态切换和空间关系变化上,时长控制在150ms到250ms之间,缓动用ease-out。
具体来说,按钮hover变色用150ms,卡片hover浮起用200ms,模态框弹出用250ms,列表项增删用200ms。这些动效不需要多复杂,但有了之后页面会显得“活”。
提示词里可以这样写:“所有transition时长使用150ms或200ms,缓动函数使用ease-out,禁止使用bounce、elastic等夸张缓动,禁止对width、height做动画(用transform代替)。”
7.3 响应式断点也要令牌化
新手做响应式经常是这里加一个@media (max-width: 768px),那里加一个@media (max-width: 640px),断点值五花八门。我的做法是把断点也做成令牌:
--breakpoint-sm: 640px; --breakpoint-md: 768px; --breakpoint-lg: 1024px; --breakpoint-xl: 1280px;虽然CSS变量不能直接用在媒体查询里,但可以在提示词里规定:“响应式断点只允许使用640px、768px、1024px、1280px四个值,移动端优先,先写小屏样式再用min-width覆盖。”
这样AI生成的响应式代码就不会出现奇怪的断点值了。而且移动端优先的写法,比桌面端优先更容易维护,因为覆盖规则是向上叠加的,逻辑更清晰。
8. 我踩过的几个典型坑和绕行方案
8.1 令牌命名太具体,换主题时全废
刚开始做设计令牌时,我按具体颜色命名,比如--purple-500、--purple-600。结果后来想换主题色,发现所有组件里都写着var(--purple-500),换主题得全局替换,跟没令牌化一样。
后来改成语义化命名:--color-primary-500、--color-primary-600。这样换主题时只需要改令牌定义,组件代码一行不用动。这个教训让我明白,令牌的名字应该描述“用途”而不是“外观”。
同理,--color-danger-500比--color-red-500好,--color-success-500比--color-green-500好。AI在生成代码时,看到语义化的名字也更容易选对令牌。
8.2 组件粒度太粗,AI改不动
一开始我把卡片做成一整个大组件,props有十几个,AI生成调用代码时经常传错参数。后来拆成Card、Card.Header、Card.Body、Card.Footer四个子组件,每个子组件只负责自己的样式,AI生成起来就清晰多了。
这个思路叫复合组件模式,核心是把“配置”变成“组合”。AI不擅长处理复杂的配置对象,但很擅长处理嵌套的组件结构。你给它看一个<Card><Card.Header>...</Card.Header><Card.Body>...</Card.Body></Card>的示例,它就能照着生成,几乎不会出错。
8.3 提示词里塞太多示例,AI反而抓不住重点
有段时间我为了让AI理解设计系统,在提示词里塞了十几个代码示例。结果AI生成时反而开始“混搭”,把不同示例的写法拼在一起,产出四不像。
后来我把示例精简到两个:一个展示组件定义,一个展示组件调用。并且明确标注“以下示例仅用于说明代码风格,不要直接复制其中的业务逻辑”。这样AI的产出反而更稳定了。
这个经验说明,提示词的质量不在于长度,而在于信噪比。每一条约束、每一个示例,都应该是必要的。可有可无的内容,删掉比留着好。
8.4 忘了约束“空值”和“边界情况”
AI生成的代码经常在边界情况上翻车。比如列表为空时显示一片空白,数字为0时显示“0”而不是“--”,长文本溢出容器,超长用户名把布局撑破。
这些问题的根源是提示词里没提。后来我在提示词里加了一段:“所有展示数据的组件必须处理以下边界情况:空数组显示空状态、null显示占位符、超长文本用省略号截断、数字超过四位数用千分位分隔。”
加上这段之后,AI生成的代码健壮性明显提升。虽然还是会有漏网之鱼,但至少常见边界情况都覆盖到了。
9. 把整套流程固化成可复用的工作流
9.1 建立自己的提示词模板库
经过几轮迭代,我把常用的提示词固化成了几个模板:页面骨架模板、组件样式模板、代码审查模板、边界情况补全模板。每次新项目开始时,直接调用对应模板,把设计令牌和组件契约替换进去就行。
模板库不需要多复杂,一个Markdown文件就够。关键是要持续维护——每次踩坑后,把新的约束加进对应模板,下次就不会再犯同样的错。我现在的模板库有十几个模板,覆盖了从页面搭建到代码审查的全流程,基本上新项目启动半小时内就能进入生成阶段。
9.2 用脚本自动检查生成结果
手动检查毕竟费时,我把常用的检查项写成了一个Node脚本,每次生成完代码跑一遍,输出问题列表。脚本逻辑很简单,就是正则匹配加规则判断:
const rules = [ { pattern: /#[0-9A-Fa-f]{3,6}/g, message: '发现硬编码颜色值' }, { pattern: /(padding|margin|gap):\s*\d+px/g, message: '发现硬编码间距' }, { pattern: /border-radius:\s*\d+px/g, message: '发现硬编码圆角' }, { pattern: /style=\{\{/g, message: '发现内联样式' }, ]; // 遍历文件,匹配规则,输出报告这个脚本不追求完美,能筛出80%的明显问题就够用了。剩下的20%靠人工走查。脚本加人工的组合,比纯人工效率高很多。
9.3 定期回顾和更新设计令牌
设计令牌不是定完就不动的。项目推进过程中,总会遇到需要新增令牌的情况。我的习惯是每两周回顾一次,看看有没有新的硬编码值反复出现,如果有,就把它抽象成新令牌。
比如发现好几个地方都写了border: 1px solid #E5E7EB,那就新增一个--border-default: 1px solid var(--color-neutral-200)。发现好几个地方都用了font-weight: 600,那就新增--font-weight-semibold: 600。
这个回顾机制能让设计系统持续生长,而不是一开始定完就僵化。AI生成代码的合格率也会随着令牌的完善而逐步提升。
10. 一个完整的实操示例:从提示词到成品
10.1 需求描述与提示词组装
假设要做一个“团队成员列表”页面,需求是:顶部有标题和“邀请成员”按钮,下面是成员卡片网格,每张卡片显示头像、姓名、角色、状态标签,支持空状态和加载态。
我把提示词组装成三段:
角色段:“你是一名严格遵循设计系统规范的前端工程师,使用React和CSS Modules实现页面,所有样式必须引用设计令牌,不允许硬编码任何颜色、间距、字号、圆角、阴影。”
约束段:附上设计令牌定义、组件契约(Button、Card、Tag、Avatar的props)、栅格规则、边界情况要求。
示例段:给一个Card组件的定义和调用示例,一个Button的调用示例。
10.2 分步生成与检查
第一步生成骨架,产出语义化的JSX结构。第二步逐块填充样式,先写网格布局,再写卡片内部样式,最后写状态标签。第三步跑检查脚本,发现两处硬编码间距,退回修复。第四步人工走查,调整了卡片hover的阴影档位,从--shadow-sm改成--shadow-md,因为卡片是可点击的,需要更明显的悬浮反馈。
整个过程大概二十分钟,产出的代码直接合入项目,不需要二次重构。对比之前一次性生成再反复修改的方式,效率提升非常明显。
10.3 最终产出的代码结构
最终产出的组件结构是这样的:
TeamMembers/ TeamMembers.tsx # 页面容器,处理数据获取和状态 TeamMembers.module.css # 页面级布局样式 MemberCard.tsx # 成员卡片组件 MemberCard.module.css # 卡片样式 EmptyState.tsx # 空状态组件 SkeletonCard.tsx # 骨架屏组件每个组件的样式文件里,颜色、间距、字号、圆角、阴影全部引用令牌,没有一处硬编码。组件props全部使用联合类型约束,AI无法生成越界的调用代码。空状态、加载态、错误态都有对应实现,边界情况也处理了。
这套代码拿给团队里其他人看,第一反应是“这是你手写的吧”,而不是“这是AI生成的吧”。这大概就是对“抗AI味”最好的评价了。
11. 关于AI辅助前端这件事,我现在的真实看法
用了大半年AI辅助前端开发,我的感受是:AI不会让你从新手变成高手,但它能让高手把时间花在更值得的地方。设计系统、组件契约、提示词工程这些东西,本质上都是把“审美判断”和“规范约束”前置,让AI去干那些重复性的实现工作。
新手最容易陷入的误区,是期待AI直接给出“好看”的页面。但“好看”是个结果,不是原因。原因是背后有一套自洽的约束体系。你把约束体系建好了,AI自然就能产出好看的东西;约束体系没建好,AI只能给你一堆平庸的拼凑。
所以与其花时间研究“怎么让AI写出更炫的代码”,不如花时间研究“怎么把设计系统定义得更清晰”。前者是术,后者是道。道立住了,术自然就通了。
我现在的工作流基本稳定下来了:新项目启动先花半天定义令牌和组件契约,然后花半天写提示词模板,之后就是批量生成加检查。一个中等复杂度的后台页面,从需求到可用代码,大概两三个小时。这个效率在以前是不敢想的,但前提是前面那两天的“基建”工作不能省。
如果你刚开始用AI做前端,我的建议是:先别急着生成页面,先花时间把设计令牌和组件契约搭起来。哪怕只定义颜色和间距两套令牌,效果都会立竿见影。等这套流程跑顺了,再逐步补充字号、圆角、阴影、动效这些维度。一步一步来,比一上来就追求大而全的设计系统要靠谱得多。