mcpField
P
pixel-perfect-replication

pixel-perfect-replication

github.com/yu-369设计与 UI99254 次安装12 周前更新
代码仓库

关于 pixel-perfect-replication

面向根据截图、模型图或设计图编写界面的复刻技能,将图像视为实现规范,按流程提取布局、字体、颜色和组件细节,再据此编写代码。它强调先记录视觉依据,并在信息不清时询问而非猜测。

主要功能

  1. 01分类参考图与视口
  2. 02提取布局和排版参数
  3. 03记录颜色与间距体系
  4. 04盘点组件样式与纹理
  5. 05分析响应式和交互线索

适用场景

  1. 01根据网页截图复刻页面
  2. 02将 Figma 导出图转为界面代码
  3. 03从移动端参考图还原组件布局
  4. 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 生成,并描述确切的风格、颜色和构图
→ 参考图中包含照片时
  1. 首选: 使用 generate_image 创建照片,使其氛围、配色、主体和构图与参考图相符
  2. 次选: 使用 picsum.photos/seed/{descriptive-keyword}/{w}/{h},并选择与内容相符的关键词(例如,海洋图像可使用 picsum.photos/seed/ocean-waves/800/600)
  3. 绝不要: 用 CSS 渐变、条纹图案或纯色块代替照片。这是最明显的偏差
→ 参考图中包含插画或笔触时
  1. 首选: 使用 generate_image,并详细描述插画风格、颜色、笔触质感和构图。注明氛围:“有机的手绘粉色笔触,带有清晰可见的纹理,斜向横跨白色背景,珊瑚粉/亮粉色,类似富有表现力的抽象艺术”
  2. 次选: 如果无法使用 generate_image,则寻找风格和颜色相符的素材插画
  3. 绝不要: 用 CSS 渐变或几何形状近似有机手绘作品。斜向 CSS 渐变不是笔触。CSS border-radius 形成的团块不是有机形状。眼睛一眼就能看出区别
→ 参考图中包含纹理表面时

大理石、木纹、混凝土、织物、水、云——这些都需要真实的图片素材:

  1. 使用 generate_image 生成纹理,并描述具体的表面
  2. 将其设为 background-image,并使用合适的 background-size、object-fit 和定位
  3. 匹配缩放比例——放大的大理石纹理与缩小后的纹理看起来不同
→ 素材尺寸与定位

将生成的图片素材放入布局时:

/* 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 近似效果更接近参考图。


边界情况

无法识别字体时
  1. 列出最可能的 2–3 个候选字体,并说明哪个区别性字形让你更倾向于其中一个
  2. 建议用户通过开发者工具查看线上网站:DevTools → Computed Styles → font-family
  3. 默认使用最接近的 Google Font
  4. 组织 CSS,使字体可通过更改单个 --font-display 变量来替换
当参考图分辨率较低时
  1. 提取你能确信的信息(布局、配色、整体字体样式)
  2. 明确标出不确定的测量结果
  3. 请求提供更高分辨率的图片或线上网站的 URL
  4. 不要从模糊的截图中臆造亚像素细节
当参考图包含你无法复现的内容时

有些参考图会显示动态内容(实时聊天、真实用户头像、实时数据):

  1. 使用静态占位数据复现视觉效果
  2. 使用真实可信的内容——听起来像真人的姓名、自然的数字(不要使用“John Doe”或“99.99%”)
  3. 在交付内容中注明哪些元素是占位内容

对于艺术类内容(照片、插图、纹理),请参阅上方的“处理艺术素材”部分。切勿用 CSS 模拟——始终生成或获取真实图像。

当提供了多张参考图时
  1. 分别对每张图片进行完整提取
  2. 确认各图片的设计系统是否一致(字体、颜色、组件是否相同)
  3. 如果存在不一致,请询问用户哪张图片具有权威性
  4. 桌面端 + 移动端配对图:使用桌面端确定设计系统,使用移动端确定响应式断点
当参考图使用了知名组件库时

如果你发现使用了 shadcn/ui、Radix、Material 或其他组件库:

  1. 说明你认为使用的是哪个组件库
  2. 询问用户希望使用该组件库还是手动复现
  3. 如果使用组件库:正确安装并调整主题以匹配
  4. 如果手动复现:在不引入依赖的情况下匹配视觉效果

核心原则

参考图就是规范。代码是翻译。你是翻译者,而不是设计师。应匹配图片,而非个人偏好。如果参考图与审美直觉相悖,以参考图为准。唯一允许的技术性覆盖是使用 min-h-[100dvh] 替代 h-screen,因为 h-screen 是浏览器错误,而非设计选择。

评论

支持 Markdown