关于 pixel-perfect-replication
面向根据截图、模型图或设计图编写界面的复刻技能,将图像视为实现规范,按流程提取布局、字体、颜色和组件细节,再据此编写代码。它强调先记录视觉依据,并在信息不清时询问而非猜测。
主要功能
- 01分类参考图与视口
- 02提取布局和排版参数
- 03记录颜色与间距体系
- 04盘点组件样式与纹理
- 05分析响应式和交互线索
适用场景
- 01根据网页截图复刻页面
- 02将 Figma 导出图转为界面代码
- 03从移动端参考图还原组件布局
- 04在编码前标记设计中的模糊细节
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yu-369/ vibecurb --skill pixel-perfect-replication安装后在 Claude Code 中输入/pixel-perfect-replication确认已加载。
详细介绍
像素级精准复刻设计
当用户提供截图、模型图、Figma 导出图或任何设计图片,并要求你用代码复刻时,此技能便会触发。参考图片就是规范。你的角色是翻译者,而非设计师。每项视觉决策——字体大小、间距、颜色、圆角、阴影、布局比例——都应以图片为依据,而非个人偏好。
工作流程
每项复刻任务都必须遵循此流程。不得跳过任何阶段。上一阶段完成前,不得开始下一阶段。
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ IMAGE IN ──→ Phase 1: Intake ──→ Phase 2: Deep Extraction │
│ (classify) (7 layers, fill sheets) │
│ │
│ ──→ Phase 3: Build │
│ (structure-first, exact CSS) │
│ │
│ ──→ Phase 4: Visual Diff │
│ (verify against reference) │
│ │
│ Each phase has a ✓ Quality Gate. Failing a gate blocks the next. │
│ │
└─────────────────────────────────────────────────────────────────────┘
阶段 1:接收图片
接收参考图片。开始处理前,先判断图片的类型。
→ 判断图片类型
为每张参考图片填写此表:
| 字段 | 你的答案 |
|---|---|
| 图片类型 | 整页截图 / 单个版块 / 组件详情 / 移动端视图 / 桌面端视图 / Figma 画板 / 设计工具导出图 / 线上网站截图 |
| 可见版块 | 按从上到下的顺序列出,例如:“导航 → 主视觉 → 功能 → 用户评价 → 页脚” |
| 目标视口 | 估算宽度:1440px(桌面端)、1280px(笔记本电脑)、768px(平板)、375px(移动端) |
| 保真度 | 高分辨率导出图(亚像素细节均为有意设计)/ 压缩截图(存在一些有损压缩痕迹) |
| 主题 | 浅色 / 深色 / 混合 |
→ 输出提取摘要
编写任何代码之前,用结构化的自然语言说明你看到的内容。这将为后续所有决策提供依据。
示例:
浅色模式,1440px 桌面端。共五个版块:带毛玻璃效果的粘性导航栏,左侧为 Logo / 中间为链接 / 右侧为 CTA;主视觉区域左对齐的大型衬线标题,叠加在铺满版面的摄影图片上;三列功能网格,卡片图标置顶;带有大号引号的用户评价轮播;极简页脚,含四列链接。配色:暖奶油色底色、近黑色文字、CTA 采用陶土色强调色。字体:衬线展示字体(可能是 Playfair Display),几何无衬线正文字体(可能是 Outfit)。卡片采用直角设计,按钮为胶囊形。没有明显阴影——整体为扁平设计,仅以细微边框分隔。
→ 图片不清晰时
不要猜测。请针对具体问题提问:
“当前分辨率下,导航链接挤在一起,无法辨认。正文字体可能是 Outfit,也可能是 Satoshi——在这个字号下,两者的字形几乎相同。你能否提供导航栏的局部放大图,或确认字体栈?”
✓ 质量检查:接收图片
进入阶段 2 前,请确认:
- 已判断图片类型、版块数量、视口和保真度
- 已编写提取摘要
- 已标记任何不清晰之处并请求澄清(或确认所有内容均清晰可辨)
阶段 2:深入提取
对参考图片执行全部七个提取层级。每个层级聚焦于设计的一个维度。针对每个层级填写提取表。跳过任何层级都会造成偏差——这里的小误差会累积,最终导致成品“看起来不对”。
第 1 层:布局网格
提取空间骨架。
提取表:
| 属性 | 测量值 |
|---|---|
| 容器最大宽度 | 例如 1280px、1440px——根据内容边缘与视口边缘的比例测量 |
| 列系统 | 例如 grid-cols-[1.15fr_1fr]、grid-cols-3、single column centered |
| 水平内边距 | 例如 px-6 md:px-12 lg:px-20——测量内容边缘与视口边缘之间的间距 |
| 区块高度 | 全视口高度使用 min-h-[100dvh],由内容决定时使用 auto |
| 区块间距 | 区块之间的垂直间距,例如 py-24 lg:py-32 |
| 对齐方式 | 按区块分别设置:左对齐/居中/右对齐/混合 |
| Z 轴层级 | 是否存在重叠?元素是否叠放在其他元素之上? |
如何根据图像测量比例:
- 如果主视觉标题约占视口宽度的 60%,那么在 1440px 的目标尺寸下,宽度大约为
max-w-[54rem] - 如果一列在视觉上比相邻列宽 1.5 倍,使用
grid-cols-[1.5fr_1fr] - 如果标题上方的留白约为标题字号的 2 倍,则内边距约为标题字号的
2em
⚠ 偏差警告: 最常见的布局错误是容器最大宽度设置不当。使用 max-w-[1200px] 的设计与使用 max-w-[1440px] 的设计看起来会有明显差异——留白比例会完全改变。请仔细测量。
第 2 层:字体排印
这是最关键的提取步骤。字体排印不对,是复刻结果“看起来不对劲”的头号原因。
提取表(为每个可见文本元素填写):
| 元素 | 字体系列 | 字重 | 字号 | 行高 | 字间距 | 转换 | 颜色 |
|---|---|---|---|---|---|---|---|
| 导航链接 | |||||||
| 眉题/标签 | |||||||
| H1(主视觉区) | |||||||
| H2(版块) | |||||||
| H3(卡片标题) | |||||||
| 正文 | |||||||
| 说明文字/元信息 | |||||||
| CTA 文案 | |||||||
| 页脚链接 |
识别字体——观察要点:
字体会通过特定字符显露特征。猜测之前,先仔细观察这些字符:
| 检查的字符 | 可判断的特征 |
|---|---|
小写 a | 单层结构(Geist、Helvetica)还是双层结构(Outfit、Satoshi、DM Sans) |
小写 g | 开放式尾部(大多数无衬线字体)还是封闭式尾部(Futura,以及一些几何字体) |
小写 t | 弯曲的横画(人文主义风格:Manrope、Jakarta)还是平直的横画(几何风格:Outfit、Satoshi) |
大写 R | 直腿(Geist、Helvetica)还是弯腿(Outfit、Satoshi) |
大写 Q | 不同字体的尾部样式差异很大,是很有力的识别特征 |
小写 e | 高横画(几何风格)还是居中横画(人文主义风格) |
数字 1, 4, 6, 9 | 不同字体中的字形差异非常鲜明 |
常见网页字体速查表:
| 视觉特征 | 优先考虑的字体 |
|---|---|
几何风格、双层结构的 a、圆形字腔 | Outfit、Satoshi、DM Sans、Plus Jakarta Sans |
哥特风格、单层结构的 a、平直的字端 | Geist、Suisse Intl、Helvetica Neue |
| 人文主义风格、开放式字腔、书法式笔势 | Manrope、Plus Jakarta Sans、Nunito Sans |
| 窄体、高 x 高度 | Barlow Condensed、Oswald、Archivo Narrow |
| 现代衬线体、高对比度、尖锐衬线 | Playfair Display、Bodoni Moda |
| 过渡型衬线体、中等对比度 | Lora、Merriweather、Source Serif Pro |
| 展示型无衬线体、字面宽、字重粗 | Cabinet Grotesk、Clash Display、Monument Extended |
| 等宽字体 | JetBrains Mono、Fira Code、IBM Plex Mono、Geist Mono、Space Mono |
如果无法有把握地识别字体,请列出最可能的 2–3 个候选字体,并说明让你倾向其中某个字体的区别性字符。例如:“双层结构的 ‘a’ 和圆形的 ‘o’ 表明可能是 Outfit,但略带方角的字端也可能意味着 Satoshi。先使用 Outfit——如果不对,修改 --font-display 即可切换。”
⚠ **偏差警告:**不要因为“标题应该是粗体”就假定标题的 font-weight: 700。许多高端设计会为标题使用 500 或 600 的字重,并搭配字面更粗的字体。请观察笔画相对于字腔的粗细。
第 3 层:色彩调色板
提取每一种不同的颜色。不要只说“用了蓝色”——要提取十六进制值。
提取表:
| 角色 | 十六进制值 | 备注 |
|---|---|---|
| 背景(主色) | 例如,#F5F0EB 暖米白,而非纯 #FFFFFF | |
| 背景(次色) | 替代区块背景、卡片背景 | |
| 背景(深色区块) | 如果有区块切换为深色 | |
| 文本(主色) | 主背景上的标题和正文 | |
| 文本(次色) | 弱化的描述、元数据 | |
| 文本(三级) | 占位符、禁用状态 | |
| 强调色 | CTA、活动指示器、链接 | |
| 强调色(悬停) | 交互时更深/更浅的变体 | |
| 边框 | 卡片边框、分隔线、输入框边框 | |
| 阴影 | 如果带有色调,请注明色相 |
从压缩截图中提取颜色:
截图压缩会改变颜色。要获取准确值:
- 从颜色的最大平坦区域取样,而不是边缘或 JPEG 伪影处
- 与常见的 Web 色值交叉比对——如果测得
#0b0b0b,它几乎肯定是标准的近黑色#0a0a0a。如果测得#f4f3f1,它可能是常见的暖米白#f5f4f2 - 提取后,检查文本颜色与背景颜色之间的 WCAG AA 对比度,以确认数值合理
⚠ 偏差警告: #FFFFFF(纯白)与 #F5F0EB(暖米白)之间的差异,会彻底改变页面的感觉。除非参考图确实显示纯色,否则不要默认使用 #FFFFFF 或 #000000——大多数高端设计都会使用近白色和近黑色。
第 4 层:间距系统
间距决定了设计是“看起来接近”还是“看起来一模一样”。
提取表:
| 测量项 | 值 | 验证方式 |
|---|---|---|
| 基础单位 | 4px 或 8px | 测量最小的重复间距 |
| 按钮内边距(水平) | 例如,24px / px-6 | 文本边缘与按钮边缘之间的水平空间 |
| 按钮内边距(垂直) | 例如,12px / py-3 | 垂直空间 |
| 卡片内部内边距 | 例如,32px / p-8 | 卡片边缘到卡片内容的空间 |
| 网格间距 | 例如,24px / gap-6 | 卡片/列之间的空间 |
| 标题 → 副文本 | 例如,16px / mt-4 | 标题基线与副文本顶部之间的间距 |
| 副文本 → CTA | 例如,32px / mt-8 | 副文本与按钮之间的间距 |
| 区块顶部内边距 | 例如,96px / pt-24 | 区块顶部到第一个元素的空间 |
| 区块底部内边距 | 例如,128px / pb-32 | 最后一个元素到区块底部的空间 |
| 导航栏高度 | 例如,64px / h-16 | 导航栏的总高度 |
| 导航链接间距 | 例如,32px / gap-8 | 导航链接之间的空间 |
⚠ 偏差警告: 区块顶部和底部的内边距通常并不相等。为了实现视觉平衡,许多设计会设置比顶部更大的底部内边距(或反之)。如果参考图显示 pt-20 pb-28,不要想当然地使用 py-24。应分别测量两侧。
第 5 层:组件清单
整理图像中可见的每一种不同 UI 组件。
为每个组件填写:
| 组件 | 形状(圆角半径) | 边框 | 阴影 | 背景 | 可见状态 | 图标样式 |
|---|---|---|---|---|---|---|
| 主按钮 | ||||||
| 次按钮 | ||||||
| 卡片 | ||||||
| 输入框 | ||||||
| 徽章/胶囊 | ||||||
| 头像 | ||||||
| 导航栏 | ||||||
| 分隔线 |
边框圆角一致性检查: 大多数设计都会采用统一的圆角风格。检查设计使用的是:
- 直角——处处使用
0px(粗野主义、编辑风格) - 微圆角——处处使用
4-8px(SaaS、产品) - 圆角——处处使用
12-16px(现代、友好) - 胶囊形——按钮使用
9999px,卡片使用圆角(高端、精致) - 混合——不同组件使用不同圆角(逐一核实)
⚠ 偏差警告: 如果参考图中的按钮是胶囊形(rounded-full),代码中就不能使用 rounded-lg。圆角不匹配会一眼可见——相比颜色或间距错误,人眼更容易察觉圆角差异。
第 6 层:氛围与质感
提取让设计显得鲜活而非扁平的细微细节。
提取表:
| 属性 | 是否存在? | 细节 |
|---|---|---|
| 噪点/颗粒叠加层 | 是/否 | 不透明度(通常为 0.03-0.06) |
| 径向环境光晕 | 是/否 | 位置、颜色、扩散范围 |
| 磨砂玻璃(backdrop-blur) | 是/否 | 应用于哪些元素、模糊程度 |
| 渐变背景 | 是/否 | 方向、色标、颜色 |
| 着色阴影 | 是/否 | 阴影色调,而不只是黑色 |
| 图片叠加层/遮罩 | 是/否 | 渐变方向、不透明度 |
| 背景图片/图案 | 是/否 | 细微纹理、圆点、线条 |
| 深度/层次感 | 扁平/细微/厚重 | 整体阴影用法 |
第 7 层:响应式线索与交互推断
即使只有静态图片,也要提取行为线索。
提取表:
| 信号 | 推断 |
|---|---|
| 多栏布局 | 在 768px 以下会折叠为单栏 |
| 水平导航栏 | 在 768px 以下需要移动端菜单 |
| 看起来固定的导航栏 | 可能使用 position: fixed; top: 0 并搭配 backdrop-blur |
| 元素位置看起来像“刚刚落下” | 暗示入场动画(淡入上移并依次错开) |
| 有视觉深度的按钮 | 悬停时上移(translateY(-1px),阴影加深) |
| 带边框的卡片 | 悬停时改变边框颜色或微调背景 |
| 图片附近的圆点指示器 | 轮播/滑块组件 |
| 活跃/选中标签的样式 | 带状态管理的标签页组件 |
| 可见的表单输入框 | 需要焦点环和验证状态 |
✓ 质量关卡:提取
进入第 3 阶段前,请确认:
- 已填写全部七张提取表
- 已说明字体候选及其理由
- 每种不同的颜色都有对应的十六进制值
- 间距数值均经过测量,而非臆测
- 组件清单完整,并记录了每个组件的圆角、边框和阴影
- 任何不明确之处都已标记并告知用户
第 3 阶段:构建
从这里开始实现。严格按照以下顺序构建——每一步都依赖前一步。
→ 步骤 1:全局基础
先设置设计令牌。其他所有内容都将引用这些令牌。
/* BLUEPRINT: Global tokens
WHY: Setting these first means every component inherits
the correct base values. Changing a token here updates
the entire page. */
@import url('https://fonts.googleapis.com/css2?family=FONT_NAME:wght@300;400;500;600;700&display=swap');
:root {
/* Colors - from Extraction Sheet Layer 3 */
--color-bg: #____;
--color-surface: #____;
--color-text: #____;
--color-text-2: #____;
--color-text-3: #____;
--color-accent: #____;
--color-accent-hover: #____;
--color-border: rgba(_, _, _, _);
/* Typography - from Extraction Sheet Layer 2 */
--font-display: 'FONT_NAME', Georgia, serif;
--font-body: 'FONT_NAME', system-ui, sans-serif;
--font-mono: 'FONT_NAME', monospace;
/* Spacing - from Extraction Sheet Layer 4 */
--space-section: clamp(5rem, 10vw, 8rem);
--space-component: 2rem;
--space-element: 1rem;
/* Radius - from Extraction Sheet Layer 5 */
--radius-card: __px;
--radius-button: __px;
--radius-input: __px;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--font-body);
font-size: 1rem; /* Adjust if reference base is not 16px */
line-height: 1.6; /* From extraction */
color: var(--color-text);
background-color: var(--color-bg);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
→ 步骤 2:布局骨架
使用正确尺寸构建各个区块容器。暂不添加内容——只搭建盒子。
/* BLUEPRINT: Section containers
WHY: Getting the spatial structure right first prevents
cascading spacing errors when content is added. */
.section {
width: 100%;
max-width: ____px; /* From Layer 1 extraction */
margin: 0 auto;
padding: var(--space-section) clamp(1.5rem, 5vw, 5rem);
}
/* Full-viewport section */
.section--full {
min-height: 100dvh;
/* WHY dvh not vh: vh causes a layout jump on iOS Safari
when the address bar collapses. dvh accounts for this. */
display: flex;
flex-direction: column;
justify-content: center;
}
/* Grid layouts - adjust columns to match reference */
.grid-2-asymmetric {
display: grid;
grid-template-columns: 1.15fr 1fr; /* From Layer 1 */
align-items: center;
gap: 4rem;
}
.grid-3-equal {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem; /* From Layer 4 */
}
@media (max-width: 768px) {
.grid-2-asymmetric,
.grid-3-equal {
grid-template-columns: 1fr;
gap: 2rem;
}
}
→ 步骤 3:排版处理
应用第 2 层提取表中的所有文本样式。
/* BLUEPRINT: Typography scale
WHY: Every property is explicitly set from the extraction.
Never rely on browser defaults - they will drift. */
.heading-display {
font-family: var(--font-display);
font-size: clamp(2.5rem, 6vw, 5rem); /* From extraction */
font-weight: 700; /* Verified from stem thickness, not assumed */
line-height: 0.95; /* Tight - measured from baseline gap */
letter-spacing: -0.03em; /* Negative - measured from character proximity */
color: var(--color-text);
text-wrap: balance;
max-width: 18ch; /* Prevents 4+ line wraps */
}
.heading-section {
font-family: var(--font-display);
font-size: clamp(1.75rem, 4vw, 3rem);
font-weight: 600;
line-height: 1.1;
letter-spacing: -0.02em;
color: var(--color-text);
}
.body-text {
font-family: var(--font-body);
font-size: clamp(0.9375rem, 1.1vw, 1.125rem);
font-weight: 400;
line-height: 1.65;
color: var(--color-text-2);
max-width: 55ch; /* Comfortable reading width */
}
.eyebrow {
font-family: var(--font-mono);
font-size: 0.6875rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-text-3);
}
.caption {
font-size: 0.8125rem;
line-height: 1.5;
color: var(--color-text-3);
}
⚠ 偏差警告: 不要为了取整而调整字号。如果提取结果显示正文为 15px,就使用 0.9375rem,而不是 1rem。如果标题看起来是 72px,就使用 4.5rem,而不是 5rem。取整误差会在整个页面上累积。
→ 步骤 4:组件处理
根据第 5 层提取表构建各个组件。
/* BLUEPRINT: Button - primary
WHY: Padding, radius, and font-size are from the extraction.
The transition easing (0.16, 1, 0.3, 1) gives a snappy
deceleration that feels physical. */
.btn-primary {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem; /* From Layer 4 */
font-family: var(--font-body);
font-size: 0.875rem; /* From Layer 2 */
font-weight: 600;
letter-spacing: 0.04em; /* Only if extraction shows tracking */
text-transform: uppercase; /* Only if extraction shows uppercase */
border-radius: var(--radius-button);
background: var(--color-accent);
color: #FFFFFF;
border: none;
cursor: pointer;
text-decoration: none;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.btn-primary:hover {
background: var(--color-accent-hover);
transform: translateY(-1px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
.btn-primary:active {
transform: translateY(0) scale(0.98);
}
.btn-primary:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
}
/* BLUEPRINT: Button - ghost/outline */
.btn-ghost {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
font-family: var(--font-body);
font-size: 0.875rem;
font-weight: 500;
border-radius: var(--radius-button);
background: transparent;
color: var(--color-text);
border: 1px solid var(--color-border);
cursor: pointer;
text-decoration: none;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.btn-ghost:hover {
border-color: var(--color-text);
background: rgba(0, 0, 0, 0.03);
}
/* BLUEPRINT: Card */
.card {
background: var(--color-surface);
border-radius: var(--radius-card);
padding: var(--space-component);
border: 1px solid var(--color-border);
/* Shadow: only add if extraction shows shadow */
}
/* BLUEPRINT: Navigation */
.nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 50;
height: 64px; /* From Layer 4 extraction */
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 clamp(1.5rem, 5vw, 5rem);
background: rgba(255, 255, 255, 0.85); /* Adjust to match */
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border-bottom: 1px solid var(--color-border);
}
.nav-link {
font-size: 0.875rem;
font-weight: 500;
color: var(--color-text-2);
text-decoration: none;
transition: color 0.2s ease;
}
.nav-link:hover {
color: var(--color-text);
}
→ 步骤 5:间距调整
逐一检查所有元素间距,并对照第 4 层提取表进行核验。这是实现中最容易出现偏差的环节。
→ 步骤 6:氛围处理
根据第 6 层提取表添加纹理和深度。只添加参考图中呈现的效果。
/* BLUEPRINT: Noise/grain overlay
WHY: Breaks digital flatness. Only add if the reference
shows subtle texture on the background.
Uses position:fixed so the grain doesn't scroll. */
.grain-overlay {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 9999;
opacity: 0.04; /* Adjust to match reference intensity */
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='1'/%3E%3C/svg%3E");
}
/* BLUEPRINT: Ambient radial glow
WHY: Adds depth to flat dark backgrounds. Only use if the
reference shows a subtle light center. */
.ambient-glow {
position: absolute;
inset: 0;
background: radial-gradient(
ellipse 60% 50% at 50% 40%,
rgba(255, 255, 255, 0.035) 0%,
transparent 70%
);
pointer-events: none;
}
/* BLUEPRINT: Frosted glass surface
WHY: For navs or overlays that show content blurring through.
saturate(180%) makes colors pop through the blur layer. */
.surface-frosted {
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
}
⚠ 偏差警告: 如果参考图中没有噪点、光晕或模糊效果,就不要添加。这些是氛围细节,不是默认效果。添加参考图中不存在的纹理属于主观诠释,而非复刻。
→ 步骤 7:响应式处理
如果参考图仅展示桌面端,请根据布局结构推断移动端行为。如果同时提供了桌面端和移动端参考图,就要精确匹配两者。
/* BLUEPRINT: Mobile collapse
WHY: Every multi-column layout must collapse to single-column.
Touch targets must be minimum 44px for accessibility. */
@media (max-width: 768px) {
.grid-2-asymmetric,
.grid-3-equal {
grid-template-columns: 1fr;
}
.heading-display {
/* clamp() already handles this, but verify the minimum */
max-width: 100%;
}
.nav {
/* May need a hamburger menu implementation */
}
/* Touch targets */
.btn-primary,
.btn-ghost,
.nav-link {
min-height: 44px;
}
}
→ 步骤 8:交互处理
添加悬停状态和入场动画。静态图片无法展示交互,但每个交互元素都需要提供反馈。
/* BLUEPRINT: Staggered entry animation
WHY: Elements that fade+slide in feel intentional.
The blur-to-sharp adds perceived quality.
prefers-reduced-motion disables for accessibility. */
@keyframes enter {
from {
opacity: 0;
transform: translateY(24px);
filter: blur(6px);
}
to {
opacity: 1;
transform: translateY(0);
filter: blur(0);
}
}
.animate-in {
animation: enter 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.animate-in:nth-child(1) { animation-delay: 0.05s; }
.animate-in:nth-child(2) { animation-delay: 0.15s; }
.animate-in:nth-child(3) { animation-delay: 0.25s; }
.animate-in:nth-child(4) { animation-delay: 0.35s; }
@media (prefers-reduced-motion: reduce) {
.animate-in {
animation: none;
opacity: 1;
transform: none;
filter: none;
}
}
/* Universal interactive transition */
a, button, [role="button"], input, select, textarea {
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
✓ 质量门禁:构建
进入阶段 4 之前,请确认:
- 全局令牌根据提取值设置,而不是使用默认值
- 布局骨架与参考图的区块结构一致
- 每项排版属性都使用了明确的值(没有浏览器默认值)
- 组件的圆角、边框、阴影和内边距与提取表一致
- 已对照参考图核验元素之间的间距
- 仅在参考图中呈现的氛围效果才会添加
- 已实现响应式折叠
- 所有交互元素都设置了悬停/焦点状态
阶段 4:视觉差异对比
将你的实现与参考图进行对比。这是最终核验。逐项检查以下类别,并标记为通过或失败。任何失败项都会阻止交付。
布局差异
| 检查项 | 通过/失败 |
|---|---|
| 区块数量和顺序一致 | |
| 容器最大宽度的比例一致 | |
| 水平内边距一致 | |
| 网格列数和比例一致 | |
| 区块高度的比例基本正确 | |
| 区块之间的垂直间距一致 | |
| 各区块内元素的对齐方式(左/居中/右)一致 | |
| Z 轴层级一致(如适用) |
排版差异
| 检查项 | 通过/失败 |
|---|---|
| 字体系列已加载且显示正确 | |
| 标题字号相对于视口的比例正确 | |
| 标题字重一致(不过细,也不过粗) | |
| 标题行高一致(紧凑或宽松) | |
| 标题字间距一致(紧密或宽松) | |
| 正文字号一致 | |
| 正文行高和最大宽度一致 | |
| 眉题/标签样式一致(字号、大小写、字距、字体) | |
| 各类元素的文字颜色一致 |
颜色差异
| 检查项 | 通过/失败 |
|---|---|
| 主背景颜色一致(应为 #F5F0EB 时,不应使用 #FFF) | |
| 文字颜色(主要和次要)一致 | |
| 强调色一致 | |
| 边框/分隔线颜色一致 | |
| 各区块之间没有意外的颜色偏差 |
组件差异
| 检查项 | 通过/失败 |
|---|---|
| 按钮圆角一致(胶囊形、圆角或直角) | |
| 按钮内边距一致 | |
| 按钮文字样式一致(字号、字重、大小写、字距) | |
| 卡片样式一致(圆角、内边距、边框、阴影) | |
| 导航栏一致(高度、背景处理、链接样式) | |
| 图片处理方式一致(圆角、宽高比、object-fit) |
间距差异
| 检查项 | 通过/失败 |
|---|---|
| 标题 → 副文本的间距一致 | |
| 副文本 → CTA 的间距一致 | |
| 卡片内部内边距一致 | |
| 元素之间的网格间距一致 | |
| 区块内边距(顶部和底部分别核验)一致 | |
| 整体留白/负空间恰当 |
氛围差异
| 检查项 | 通过/失败 |
|---|---|
| 背景氛围一致(纯色/颗粒/渐变/辉光) | |
| 阴影的存在与强度一致 | |
| 参考图中有毛玻璃/模糊效果的位置均已实现 | |
| 没有添加参考图中不存在的氛围效果 |
技术检查
| 检查项 | 通过/失败 |
|---|---|
| 控制台错误为零 | |
| 所有字体均已加载(无 FOUT/FOIT) | |
| 所有图片均已加载(无损坏的占位图) | |
| 任意视口下均无水平溢出 | |
| 所有交互元素均有悬停状态 | |
| 键盘导航均有 focus-visible 状态 | |
使用了 min-h-[100dvh],而非 h-screen | |
遵循 prefers-reduced-motion 设置 |
处理艺术素材(照片、插画、纹理)
CSS 可以复现布局、排版、颜色和几何形状,但无法复现照片、手绘插画、有机笔触、大理石纹理或绘画效果。这是参考图与输出结果之间出现偏差的首要原因。
→ 对参考图中的每个视觉元素进行分类
查看参考图并标记每个视觉元素:
| 元素类型 | CSS 能否复现? | 替代做法 |
|---|---|---|
| 纯色块 | ✅ 能 | 使用提取到的精确十六进制颜色值 |
| 线性/径向渐变 | ✅ 能 | 匹配方向、色标和颜色 |
| 几何形状(圆形、矩形、线条) | ✅ 能 | 使用 CSS 形状或简单 SVG |
| 图标(描边/填充) | ✅ 能 | 使用图标库或内联 SVG |
| 照片 | ❌ 不能 | 生成符合氛围的图片,或使用 picsum.photos/seed/{keyword}/{w}/{h} |
| 手绘插画 | ❌ 不能 | 使用 generate_image 工具生成风格相符的插画 |
| 有机笔触/颜料纹理 | ❌ 不能 | 生成为图片素材——不要用 CSS 渐变近似 |
| 大理石/流体/有机纹理 | ❌ 不能 | 生成为图片素材,或使用高质量的匹配素材 |
| 3D 渲染图 | ❌ 不能 | 生成风格相符的渲染图,或使用光照/角度相近的占位图 |
| 抽象艺术/混合媒介 | ❌ 不能 | 使用 generate_image 生成,并描述确切的风格、颜色和构图 |
→ 参考图中包含照片时
- 首选: 使用
generate_image创建照片,使其氛围、配色、主体和构图与参考图相符 - 次选: 使用
picsum.photos/seed/{descriptive-keyword}/{w}/{h},并选择与内容相符的关键词(例如,海洋图像可使用picsum.photos/seed/ocean-waves/800/600) - 绝不要: 用 CSS 渐变、条纹图案或纯色块代替照片。这是最明显的偏差
→ 参考图中包含插画或笔触时
- 首选: 使用
generate_image,并详细描述插画风格、颜色、笔触质感和构图。注明氛围:“有机的手绘粉色笔触,带有清晰可见的纹理,斜向横跨白色背景,珊瑚粉/亮粉色,类似富有表现力的抽象艺术” - 次选: 如果无法使用
generate_image,则寻找风格和颜色相符的素材插画 - 绝不要: 用 CSS 渐变或几何形状近似有机手绘作品。斜向 CSS 渐变不是笔触。CSS
border-radius形成的团块不是有机形状。眼睛一眼就能看出区别
→ 参考图中包含纹理表面时
大理石、木纹、混凝土、织物、水、云——这些都需要真实的图片素材:
- 使用
generate_image生成纹理,并描述具体的表面 - 将其设为
background-image,并使用合适的background-size、object-fit和定位 - 匹配缩放比例——放大的大理石纹理与缩小后的纹理看起来不同
→ 素材尺寸与定位
将生成的图片素材放入布局时:
/* BLUEPRINT: Image asset inside a card or container
WHY: object-fit:cover ensures the image fills the space
without distortion. object-position lets you align the
focal point of the image to match the reference. */
.asset-container {
position: relative;
overflow: hidden;
border-radius: var(--radius-card); /* match card radius */
}
.asset-image {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center; /* adjust to match reference focal point */
}
⚠ 偏差警告: 这是最常见的复现失败。当 AI 无法复现艺术元素时,会用 CSS 图案(条纹、渐变、纯色块)替代。这看起来总是不对,因为几何 CSS 图案的视觉质感与照片或手绘艺术有本质区别。始终生成图片素材——即使生成的图片不够完美,也比 CSS 近似效果更接近参考图。
边界情况
无法识别字体时
- 列出最可能的 2–3 个候选字体,并说明哪个区别性字形让你更倾向于其中一个
- 建议用户通过开发者工具查看线上网站:DevTools → Computed Styles →
font-family - 默认使用最接近的 Google Font
- 组织 CSS,使字体可通过更改单个
--font-display变量来替换
当参考图分辨率较低时
- 提取你能确信的信息(布局、配色、整体字体样式)
- 明确标出不确定的测量结果
- 请求提供更高分辨率的图片或线上网站的 URL
- 不要从模糊的截图中臆造亚像素细节
当参考图包含你无法复现的内容时
有些参考图会显示动态内容(实时聊天、真实用户头像、实时数据):
- 使用静态占位数据复现视觉效果
- 使用真实可信的内容——听起来像真人的姓名、自然的数字(不要使用“John Doe”或“99.99%”)
- 在交付内容中注明哪些元素是占位内容
对于艺术类内容(照片、插图、纹理),请参阅上方的“处理艺术素材”部分。切勿用 CSS 模拟——始终生成或获取真实图像。
当提供了多张参考图时
- 分别对每张图片进行完整提取
- 确认各图片的设计系统是否一致(字体、颜色、组件是否相同)
- 如果存在不一致,请询问用户哪张图片具有权威性
- 桌面端 + 移动端配对图:使用桌面端确定设计系统,使用移动端确定响应式断点
当参考图使用了知名组件库时
如果你发现使用了 shadcn/ui、Radix、Material 或其他组件库:
- 说明你认为使用的是哪个组件库
- 询问用户希望使用该组件库还是手动复现
- 如果使用组件库:正确安装并调整主题以匹配
- 如果手动复现:在不引入依赖的情况下匹配视觉效果
核心原则
参考图就是规范。代码是翻译。你是翻译者,而不是设计师。应匹配图片,而非个人偏好。如果参考图与审美直觉相悖,以参考图为准。唯一允许的技术性覆盖是使用
min-h-[100dvh]替代h-screen,因为h-screen是浏览器错误,而非设计选择。