我失去了设计师递给我一个漂亮的 Figma 文件并说"构建这个应该很简单,对吧?"的次数的统计。当然,英雄部分看起来足够简单。但当你开始深入响应式行为、未完全规范的悬停状态、在帧之间变化的间距,以及一个存在于设计师脑子里但代码中不存在的设计系统时。Figma 模型和生产 Next.js 网站之间的差距就是项目偏离轨道的地方。

在 Social Animal 构建了数十个 Figma-to-Next.js 项目后,我对哪些有效、哪些无效形成了强烈的看法。本指南贯穿整个过程——不是理论版本,而是混乱的、真实世界的版本,其中设计不完美,利益相关者改变主意,你需要交付一个在生产环境中实际性能良好的东西。

Figma to Next.js: 将设计转换为代码的完整指南

目录

为什么在 Figma 转代码项目中选择 Next.js

你可以把 Figma 设计转换为纯 HTML。你可以使用 Astro、Remix 或 SvelteKit。那么为什么选择 Next.js?

实际上有几个重要的原因:

  • React 组件模型直接映射到 Figma 组件。 设计师用组件思考。React 也用组件思考。这种对齐并非微不足道——这意味着代码中的组件树可以镜像 Figma 中的组件层次结构,这使维护变得轻松得多。
  • App Router 与 Server Components 提供营销网站和 Web 应用都需要的渲染灵活性。静态页面?服务器渲染的动态内容?客户端交互?你按路由选择。
  • 图像优化是内置的。 next/image 组件处理响应式图像、延迟加载和格式转换——否则会耗费你许多构建时间的事情。
  • 生态系统巨大。 无论设计要求什么——身份验证、表单、动画、CMS 集成——在 Next.js 生态系统中都有一个维护良好的解决方案。

我们在大多数 无头 CMS 开发项目 中使用 Next.js 正是由于这些原因。如果你想了解什么时候 Astro 可能更适合(提示:内容丰富、交互最少的网站),请查看我们的 Astro 开发 页面。

在编写任何代码前审计 Figma 文件

这是大多数开发者跳过的步骤,也是节省最多时间的步骤。在你编写单行 JSX 之前,花 30-60 分钟审计 Figma 文件。

要检查的内容

  • 自动布局使用。 如果设计师一致地使用了自动布局,你的生活会变得轻松得多。自动布局几乎 1:1 映射到 flexbox。如果他们没有,你将猜测间距和响应式行为。
  • 组件一致性。 按钮是否真正使用了共享组件,还是设计师在帧中创建了 14 个略微不同的按钮变体?打开资源面板检查。
  • 命名样式和变量。 Figma 变量(2023 年发布,2025 年被广泛采用)应该定义颜色、间距、排版和边框半径。如果存在这些,你的设计令牌提取大多是自动化的。如果没有,在开始构建前标记。
  • 响应式框架。 设计是否包括移动端、平板和桌面端断点?如果仅限桌面端,你需要在继续前与设计师进行对话。
  • 缺失状态。 悬停、焦点、活跃、禁用、加载、错误、空白——检查交互组件是否设计了所有状态。他们通常没有。列出清单。

交接对话

我总是在开始实现前与设计师安排 30 分钟的通话。我们屏幕共享 Figma 文件并逐步完成:

  1. 哪些组件可重用,哪些是一次性的
  2. 响应式行为应该如何工作(不要假设——要询问)
  3. 他们想到的任何动画或过渡
  4. 来自 CMS 的内容与硬编码的内容

这次单一的会议消除了 80% 通常困扰设计转代码项目的来回往复。

Figma to Next.js: 将设计转换为代码的完整指南 - 架构

从 Figma 提取设计令牌

设计令牌是 Figma 和代码之间的桥梁。颜色、排版比例、间距单位、边框半径、阴影——这些需要系统地提取,而不是凭眼睛判断。

手动提取(小项目)

对于较小的项目,我会使用 Figma 的开发模式(2025 年起,Figma 付费计划中每座位每月 $25)来直接检查值。打开开发模式,点击任何元素,你会获得精确的像素值、颜色和字体属性。

然后我将这些映射到 Tailwind CSS 配置或 CSS 自定义属性:

// tailwind.config.ts
import type { Config } from 'tailwindcss'

const config: Config = {
  theme: {
    extend: {
      colors: {
        brand: {
          50: '#f0f4ff',
          100: '#dbe4ff',
          500: '#4c6ef5',
          600: '#3b5bdb',
          700: '#364fc7',
          900: '#1c2d7a',
        },
        surface: {
          primary: '#ffffff',
          secondary: '#f8f9fa',
          tertiary: '#f1f3f5',
        },
      },
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
        display: ['Cal Sans', 'Inter', 'system-ui', 'sans-serif'],
      },
      spacing: {
        '18': '4.5rem',
        '88': '22rem',
      },
      borderRadius: {
        'xl': '1rem',
        '2xl': '1.5rem',
      },
    },
  },
}

export default config

自动提取(较大项目)

对于更大的设计系统,使用 Figma Variables API 或诸如 Tokens Studio(前身为 Figma Tokens)的工具以结构化格式导出设计令牌。Tokens Studio 可以导出为 Style Dictionary 格式,然后你将其转换为 Tailwind 配置、CSS 变量或两者。

管道看起来像这样:

Figma Variables → Tokens Studio → Style Dictionary → tailwind.config.ts + globals.css

当设计师更新颜色而你需要在整个代码库中传播它时,这种自动化在第一次就能收回成本。

设置 Next.js 项目架构

这是我为每个 Figma-to-Next.js 构建开始的项目结构:

src/
├── app/
│   ├── layout.tsx
│   ├── page.tsx
│   ├── globals.css
│   └── (routes)/
├── components/
│   ├── ui/           # 原始组件:Button、Input、Card、Badge
│   ├── layout/       # Header、Footer、Container、Section
│   ├── sections/     # Hero、Features、Testimonials、CTA
│   └── patterns/     # 组合:PricingCard、TeamMember
├── lib/
│   ├── utils.ts
│   └── fonts.ts
├── styles/
│   └── tokens.css    # 设计令牌 CSS 变量
└── types/
    └── index.ts

关键设置决策

样式方法: Tailwind CSS 是我对 Figma 转代码项目的默认选择。实用优先的方法意味着我可以将 Figma 的 padding: 24pxgap: 16pxborder-radius: 12px 直接转换为 p-6 gap-4 rounded-xl,无需上下文切换。如果项目需要像 shadcn/ui 这样的组件库,Tailwind 已经是基础。

字体加载: 始终使用 next/font 自托管字体。这是我典型的设置:

// lib/fonts.ts
import { Inter } from 'next/font/google'
import localFont from 'next/font/local'

export const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
})

export const calSans = localFont({
  src: '../assets/fonts/CalSans-SemiBold.woff2',
  variable: '--font-display',
  display: 'swap',
})

Server 与 Client 组件: 默认使用 Server 组件。只有当你真正需要浏览器 API、事件处理器或 React 钩子时才添加 'use client'。典型的营销页面可能有 90% 的 Server 组件,配合小的交互岛屿。

构建组件库

这是大部分工作进行的地方。我的方法:从最小的组件开始往上工作。

原子组件优先

从 Figma 所称的"组件"和我们所称的原始组件开始:

// components/ui/Button.tsx
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'

const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-xl font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
  {
    variants: {
      variant: {
        primary: 'bg-brand-600 text-white hover:bg-brand-700',
        secondary: 'bg-surface-secondary text-gray-900 hover:bg-surface-tertiary',
        ghost: 'text-gray-600 hover:bg-surface-secondary hover:text-gray-900',
      },
      size: {
        sm: 'h-9 px-3 text-sm',
        md: 'h-11 px-5 text-sm',
        lg: 'h-13 px-7 text-base',
      },
    },
    defaultVariants: {
      variant: 'primary',
      size: 'md',
    },
  }
)

interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {}

export function Button({ className, variant, size, ...props }: ButtonProps) {
  return (
    <button
      className={cn(buttonVariants({ variant, size }), className)}
      {...props}
    />
  )
}

注意变体名称和大小如何直接映射到 Figma 中存在的内容。如果设计师有一个在 Figma 中带有"Primary"、"Secondary"和"Ghost"变体的 Button 组件——你的代码应该镜像那些确切的名称。

组合部分

一旦原始组件构建完毕,将它们组合成页面部分:

// components/sections/Hero.tsx
import { Button } from '@/components/ui/Button'
import { Container } from '@/components/layout/Container'

export function Hero() {
  return (
    <section className="py-24 md:py-32">
      <Container>
        <div className="mx-auto max-w-3xl text-center">
          <h1 className="font-display text-4xl tracking-tight text-gray-900 md:text-6xl">
            将你的设计转换为
            <span className="text-brand-600"> 生产网站</span>
          </h1>
          <p className="mt-6 text-lg leading-relaxed text-gray-600">
            我们从你的 Figma 文件构建快速、可访问的 Next.js 网站。
          </p>
          <div className="mt-10 flex items-center justify-center gap-4">
            <Button size="lg">开始使用</Button>
            <Button variant="secondary" size="lg">了解更多</Button>
          </div>
        </div>
      </Container>
    </section>
  )
}

2025 年 AI 辅助的 Figma 转代码工具

让我们谈论房间里的大象:声称自动将 Figma 转换为代码的 AI 工具。我已经测试了所有主要的工具。这是诚实的评估。

工具 最佳用途 代码质量 框架支持 价格(2025)
Fusion (Builder.io) 使用 Builder.io CMS 的团队 好——尊重设计系统 React、Next.js、Vue 包含在 Builder.io 计划中($50+/月)
Kombai 想要 AI 辅助编码的 VS Code 用户 很好——生成可编辑的计划 React、Next.js、Angular 免费层 + $20/月 Pro
Locofy.ai 快速原型和 MVP 尚可——需要清理 React、Next.js、Gatsby 免费层 + $8-25/月
Anima 响应式 HTML/React 导出 尚可——结构但不生产就绪 React、Vue、HTML 免费层 + $39/月
Figma to Code Plugin 快速 HTML 代码片段 基础——很好的起点 HTML、Tailwind 免费
v0 (Vercel) 从描述生成 UI 很好用于组件 React、Next.js 免费层 + $20/月 Pro

我的诚实看法

这些工具中没有一个生成我不经过大量修改就会直接发送到生产的代码。没有一个。以下是原因:

  • 他们生成标记但很少理解你项目的组件架构
  • 他们不知道你的数据获取模式、CMS 集成或 API 结构
  • 他们经常生成臃肿的 CSS 或不一致的类命名
  • 他们经常忽略可访问性要求

AI 工具真正有帮助的地方: 我使用 Kombai 和 v0 生成初始组件脚手架,特别是对于复杂布局。获得一个 60-70% 正确的起点可以节省真实时间。我也使用 Cursor,将 Figma 截图粘贴为上下文,以加快逐部分的实现。

真正有效的工作流程:AI 生成粗稿 → 人类开发者重构、优化和集成 → QA 发现不可避免的问题。

如果你在评估是自己做还是与代理机构合作,请查看我们的 Next.js 开发能力 以了解我们如何处理完整管道。

正确处理响应式设计

这是 Figma 转代码项目通常失败的地方。设计有一个桌面端模型和一个移动端模型。如果你幸运的话,可能还有一个平板端。但实际的行为在断点之间?这在任何人的脑子里都没有。

移动优先实现

始终编码移动优先,并在较大的断点处添加复杂性:

<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3 lg:gap-8">
  {features.map((feature) => (
    <FeatureCard key={feature.id} {...feature} />
  ))}
</div>

来自 Figma 的常见响应式模式

Figma 模式 CSS/Tailwind 实现
3 列网格 → 在移动端堆叠 grid grid-cols-1 md:grid-cols-3
并排 → 反向堆叠 flex flex-col-reverse md:flex-row
在移动端隐藏 hidden md:block
不同的字体大小 text-2xl md:text-4xl lg:text-5xl
在移动端水平滚动 flex overflow-x-auto md:grid md:grid-cols-4
导航 → 汉堡菜单 Client 组件带状态切换

容器查询(被低估的强大功能)

2025 年,容器查询拥有出色的浏览器支持(全球 95% +)。它们对需要根据其父级宽度而不是视口宽度进行自适应的组件来说是完美的:

@container (min-width: 400px) {
  .card-layout {
    flex-direction: row;
  }
}

Tailwind v4 对 @container 变体拥有原生容器查询支持。

排版和间距:大多数项目失败的地方

我估计 60% 的"它看起来不像设计"的投诉来自排版和间距,而不是布局或颜色。

排版清单

  • 字体粗细: Figma 显示"Semi Bold"即 font-semibold (600),而不是 font-bold (700)。易出错。
  • 行高: Figma 使用固定行高(如 28px),Tailwind 使用相对值(如 leading-7)。谨慎转换。
  • 字母间距: 经常被忽略。Figma 的 -2% 字母间距转换为 tracking-tight
  • 字体特性: 某些设计使用 OpenType 特性,如制表数字(font-variant-numeric: tabular-nums)或风格替代品。检查 Figma 文本属性面板。

间距系统

如果设计师使用了 8px 网格(2025 年大多数都这样),你的生活会很简单——Tailwind 的默认间距比例已经基于 4px 增量。p-4 = 16px,p-6 = 24px,p-8 = 32px。

但要注意不规则间距。如果设计在某处有 20px 填充,那是 Tailwind 中的 p-5(即 20px)。如果有 18px——这比你想象的更常见——你可以舍入到最近的步骤或扩展你的间距比例。

图像、图标和资源管道

图像

对光栅图像始终使用 next/image

import Image from 'next/image'

<Image
  src="/hero-image.webp"
  alt="显示分析的产品仪表板"
  width={1200}
  height={800}
  priority  // 为上方折叠的图像添加
  className="rounded-2xl"
/>

从 Figma 以 2 倍分辨率导出图像用于视网膜显示。使用 WebP 格式。对于英雄图像,我通常以 2400x1600 导出,让 next/image 处理响应式大小调整。

图标

不要将图标导出为图像。使用图标库或内联 SVG:

  1. Lucide React ——我的默认选择。整洁、一致、1000+ 个图标。可摇树。
  2. Heroicons ——很好,如果设计使用 Heroicons(使用 Tailwind UI 设计很常见)。
  3. 自定义 SVG ——对于品牌特定的图标,从 Figma 导出为 SVG 并创建 React 组件。
import { ArrowRight, Check, X } from 'lucide-react'

<ArrowRight className="h-5 w-5" />

动画和交互

Figma 的原型模式显示过渡和交互,但将这些转换为代码需要解释。

CSS 优先动画

对于简单的悬停效果和过渡,坚持使用 CSS:

<button className="transform transition-all duration-200 hover:scale-105 hover:shadow-lg">
  开始使用
</button>

用于复杂动画的 Framer Motion

对于滚动触发的动画、页面过渡或复杂序列:

'use client'

import { motion } from 'framer-motion'

export function FadeInSection({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true, margin: '-100px' }}
      transition={{ duration: 0.5, ease: 'easeOut' }}
    >
      {children}
    </motion.div>
  )
}

记住:这必须是一个 Client 组件。保持动画包装器精简,并在可能时将 Server 组件作为子级传递。

连接到无头 CMS

从 Figma 设计构建的大多数营销网站需要 CMS 来处理至少部分内容。这是 无头 CMS 开发 变得关键的地方。

我与 Next.js App Router 最常使用的模式:

// app/blog/[slug]/page.tsx
import { getPostBySlug } from '@/lib/cms'
import { notFound } from 'next/navigation'

export async function generateStaticParams() {
  const posts = await getAllPosts()
  return posts.map((post) => ({ slug: post.slug }))
}

export default async function BlogPost({ params }: { params: { slug: string } }) {
  const post = await getPostBySlug(params.slug)
  if (!post) notFound()

  return (
    <article className="prose prose-lg mx-auto max-w-3xl">
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  )
}

这是一个默认的 Server 组件——无需 'use client'。CMS 数据在构建时获取(使用 ISR 进行更新),为你提供快速页面加载和新鲜内容。

质量保证和设计对比

这是我对每个 Figma-to-Next.js 项目的 QA 清单:

  1. 视觉叠加对比 ——使用工具如 PixelSnap 或浏览器扩展"PerfectPixel"将 Figma 导出叠加在你构建的页面上。我的目标是 95%+ 匹配,而不是完美像素。所有浏览器和屏幕尺寸的绝对像素完美是一个神话。

  2. Lighthouse 审计 ——在全部四个评分上目标 90+。对于我们的项目,我们通常在性能上达到 95+,在可访问性上达到 100,在最佳实践上达到 100,在 SEO 上达到 100。

  3. 跨浏览器测试 ——Chrome、Firefox、Safari(特别是 Safari——总是 Safari)。在真实 iOS 设备上测试,而不仅仅是 Chrome DevTools 移动端模拟。

  4. 键盘导航 ——逐项制表符浏览每个交互元素。焦点环应该可见且逻辑清晰。

  5. 内容压力测试 ——当标题是占位符的 3 倍长时会发生什么?当图像具有不同的长宽比时?真实 CMS 内容会破坏仅适用于完美 lorem ipsum 的设计。

性能优化

一个漂亮的设计在 Lighthouse 上评分 40 是一个失败。这是我在每个项目上做的:

  • 延迟加载下方折叠图像(Next.js 默认做这个)
  • 预加载关键字体使用 next/font
  • 最小化 Client 组件 ——每个 'use client' 边界都会添加 JavaScript
  • 对重型组件使用动态导入const Chart = dynamic(() => import('./Chart'), { ssr: false })
  • 使用 next/scriptstrategy="lazyOnload" 优化第三方脚本

一个构建好的来自 Figma 设计的 Next.js 网站应该在 Lighthouse 上评分 90+,无需英勇的优化努力。如果你评分较低,你可能有太多的 Client 组件或未优化的图像。

如果你在寻求 Figma-to-Next.js 项目的帮助并想要这些类型的结果,请查看我们的 定价直接联系

常见问题

将 Figma 设计转换为 Next.js 网站需要多长时间? 这主要取决于项目的复杂性。一个 5 页的营销网站,设计系统清晰,通常需要 2-4 周的时间供一名技能娴熟的开发者。一个有数十个独特组件、自定义动画和 CMS 集成的复杂网络应用程序可能需要 6-12 周。Figma 文件质量影响很大——组织良好且具有一致组件的文件可以将开发时间减少 30-50%。

AI 工具可以完全自动化 Figma 转 Next.js 的转换吗? 还不能。截至 2025 年中期,Builder.io 的 Fusion、Kombai 和 Locofy.ai 等工具可以生成有用的起点,但没有一个在没有大量人工干预的情况下生成生产就绪的代码。它们最好被用作加速器——生成初始 60-70% 的标记——而开发者处理架构、优化、可访问性和 CMS 集成。

我应该在 Figma 转代码项目中使用 Tailwind CSS 还是 CSS Modules? Tailwind CSS 更适合大多数 Figma 转代码项目。Figma 设计表示为具体值(颜色、像素间距、字体大小),Tailwind 的实用类直接映射到那些值。CSS Modules 工作良好,但添加了一个减慢转换过程的抽象层。一个例外:如果你的团队已经有一个成熟的 CSS Modules 代码库,维护一致性可能会超过转换速度的好处。

在 Next.js 中处理 Figma 设计令牌的最佳方式是什么? 使用 Figma 变量(或 Tokens Studio 插件)以结构化格式导出令牌,然后将它们转换为你的样式系统的配置。对于 Tailwind,这意味着扩展 tailwind.config.ts。对于 CSS 自定义属性,生成一个 tokens.css 文件。亚马逊的 Style Dictionary 工具在转换格式之间的令牌方面很出色。保持管道自动化,这样设计令牌更改会传播到代码而无需手工工作。

当 Figma 文件仅有桌面端模型时,我如何处理响应式设计? 这很常见。首先,与设计师交谈并建立响应式行为期望。然后实现移动优先,根据你对设计意图的理解做出布局决策。使用 CSS Grid 和 Flexbox 创建自然响应式布局。如果你不确定,将其存根并获得实时构建的设计师反馈——在真实响应式实现上迭代比返回并设计更多静态框架快得多。

我需要 Figma 的付费计划来进行适当的 Figma 转代码开发吗? 免费计划适用于基本检查,但 Figma 的开发模式(2025 年起,付费计划中每座位每月 $25)提供显著改进的开发交接功能:CSS 代码片段、组件属性检查、精确测量和资源导出。对于专业项目,这值得成本。你的替代方案是使用免费 Figma 转代码插件或外部工具如 Locofy.ai。

我应该为 Figma 转 Next.js 构建的 Lighthouse 评分设定什么目标? 在所有类别(性能、可访问性、最佳实践、SEO)上目标 90+。Next.js 给你一个强大的起点,但你可以轻松地因未优化的图像、太多 Client 组件或重第三方脚本而摧毁你的性能评分。对于我们在 Social Animal 的项目,我们通常通过保持 Client 组件边界最少并对所有光栅图形使用 next/image 在性能上达到 95+。

我如何随时间保持 Figma 设计和 Next.js 代码库的同步? 这是持续的挑战。使用设计令牌作为单一真实来源——当 Figma 中的颜色、排版或间距更改时,更新令牌并重新生成你的 Tailwind 配置。对于组件级更改,建立一个流程:设计师更新 Figma 组件,记录改变的内容,开发者更新相应的 React 组件。像 Storybook 这样的工具可以帮助,通过提供一个设计师和开发者都可以检查 Figma 源的可视化参考。