Design to code 技术

技术概述

在互联网时代,产品的开发与迭代速度都大大快于传统的应用开发。一个完整的产品开发周期,先由产品经理完成概念框图设计,然后交由UI设计师形成视觉设计稿,最后交给开发人员实现最终的产品功能。Design to Code负责将UI设计师的视觉稿,转化为前端代码,以供后续开发,这个环节架起了UI设计师与程序开发人员之间桥梁,让两类不同专业人,可以相互沟通,紧密合作。

示例:左图为设计师提供的网站视觉稿,右图为转化为html的部分代码

<body>

  <div id="__next" data-reactroot="">
    <div class="jsx-aab0212dbcb84404 design-to-code-container">
      <div id="mobile-header" class="jsx-aab0212dbcb84404 mobile-header">
        <div class="jsx-c978c3fb180936e0 mobile-menu-light-mobilemenu  ">
          <div class="jsx-c978c3fb180936e0 mobile-menu-light-top1">
            <div class="jsx-c978c3fb180936e0 mobile-menu-light-left-side"><a
                class="jsx-c978c3fb180936e0 mobile-menu-light-link10" href="/"><img alt="teleporthq"
                  src="/Home/teleport-logo-dark-text.svg"
                  class="jsx-c978c3fb180936e0 mobile-menu-light-mobile-menu-logo"></a></div>
            <div class="jsx-c978c3fb180936e0 mobile-menu-light-right-side">
              <div class="jsx-c978c3fb180936e0 close-mobile-menu"><svg viewBox="0 0 1024 1024"
                  class="jsx-c978c3fb180936e0 close-mobile-menu-icon">
                  <title class="jsx-c978c3fb180936e0">clear, close</title>
                  <path d="M810 274l-238 238 238 238-60 60-238-238-238 238-60-60 238-238-238-238 60-60 238 238 238-238z"
                    class="jsx-c978c3fb180936e0"></path>
                </svg></div>
            </div>
          </div>
          <div class="jsx-c978c3fb180936e0 mobile-menu-light-middle">
            <div data-role="Accordion" class="jsx-c978c3fb180936e0 mobile-menu-light-product">
              <div data-role="AccordionHeader" class="jsx-c978c3fb180936e0 accordion-header"><span
                  class="jsx-c978c3fb180936e0 mobile-menu-light-text10">Product</span><svg viewBox="0 0 1024 1024"
                  data-type="AccordionArrow" class="jsx-c978c3fb180936e0 accordion-arrow">
                  <path d="M298 426h428l-214 214z" class="jsx-c978c3fb180936e0"></path>
                </svg></div>
              <div data-role="AccordionContent"
                class="jsx-c978c3fb180936e0 mobile-menu-light-content1 accordion-content"><a
                  class="jsx-c978c3fb180936e0" href="/professional-website-builder">
                  <div class="jsx-c978c3fb180936e0 mobile-menu-light-dropdown-item10"><img alt="image"
                      src="/Home/Icons/bxs-widget.svg" class="jsx-c978c3fb180936e0 mobile-menu-light-image10"><span
                      class="jsx-c978c3fb180936e0 mobile-menu-link-black">Profesional website builder</span></div>
                </a><a href="/ai-website-builder" target="_blank" rel="noreferrer noopener"
                  class="jsx-c978c3fb180936e0">
                  <div class="jsx-c978c3fb180936e0 mobile-menu-light-dropdown-item11"><img alt="image"
                      src="/Home/Icons/bxs-detail2.svg" class="jsx-c978c3fb180936e0 mobile-menu-light-image11"><span
                      class="jsx-c978c3fb180936e0 mobile-menu-link-black">AI website builder</span></div>
                </a><a class="jsx-c978c3fb180936e0" href="/headless-cms-integration">
                  <div class="jsx-c978c3fb180936e0 mobile-menu-light-dropdown-item12"><img alt="image"
                      src="/cms-icon.svg" class="jsx-c978c3fb180936e0 mobile-menu-light-image12"><span
                      class="jsx-c978c3fb180936e0 mobile-menu-link-black">Headless CMS Integrations</span></div>
                </a><a class="jsx-c978c3fb180936e0" href="/website-localization">
                  <div class="jsx-c978c3fb180936e0 mobile-menu-light-dropdown-item13"><img alt="image"
                      src="/Localization/localization1.svg" class="jsx-c978c3fb180936e0 mobile-menu-light-image13"><span
                      class="jsx-c978c3fb180936e0 mobile-menu-link-black">Localization</span></div>
                </a><a class="jsx-c978c3fb180936e0" href="/static-website-templates">
                  <div class="jsx-c978c3fb180936e0 mobile-menu-light-dropdown-item14"><img alt="image"
                      src="/Home/Icons/bxs-layout1.svg" class="jsx-c978c3fb180936e0 mobile-menu-light-image14"><span
                      class="jsx-c978c3fb180936e0 mobile-menu-link-black">Static website templates</span></div>
                </a><a class="jsx-c978c3fb180936e0" href="/free-low-code-platform">
                  <div class="jsx-c978c3fb180936e0 mobile-menu-light-dropdown-item15"><img alt="image"
                      src="/Home/Icons/bxs-devices.svg" class="jsx-c978c3fb180936e0 mobile-menu-light-image15"><span
                      class="jsx-c978c3fb180936e0 mobile-menu-link-black">Low-code development</span></div>
                </a><a class="jsx-c978c3fb180936e0" href="/real-time-code-collaboration">
                  <div class="jsx-c978c3fb180936e0 mobile-menu-light-dropdown-item16"><img alt="image"
                      src="/Home/Icons/bxs-terminal.svg" class="jsx-c978c3fb180936e0 mobile-menu-light-image16"><span
                      class="jsx-c978c3fb180936e0 mobile-menu-link-black">Code collaboration</span></div>
                </a><a class="jsx-c978c3fb180936e0" href="/static-site-generator">
                  <div class="jsx-c978c3fb180936e0 mobile-menu-light-dropdown-item17"><img alt="image"
                      src="/Home/Icons/bxl-react.svg" class="jsx-c978c3fb180936e0 mobile-menu-light-image17"><span
                      class="jsx-c978c3fb180936e0 mobile-menu-link-black">Code generators</span></div>
                </a><a class="jsx-c978c3fb180936e0" href="/figma-export-to-html-plugin">
                  <div class="jsx-c978c3fb180936e0 mobile-menu-light-dropdown-item18"><img alt="image"
                      src="/Home/Icons/bxl-figma1.svg" class="jsx-c978c3fb180936e0 mobile-menu-light-image18"><span
                      class="jsx-c978c3fb180936e0 mobile-menu-link-black">Figma plugin</span></div>
                </a></div>

UI设计稿转化为代码的工作,通常都是由前端开发人员来完成。但是这项工作繁琐重复,同时枯燥缺乏创新。如果可以将该工作自动化,不仅可以缩短设计与前端开发的鸿沟,减少大量重复劳动,也可以大幅降低前端工作的门槛,让一些初学者或设计师,快速地将设计稿转化为前端代码,实现产品原型的快速迭代。也可以提升多平台(iOS,Android,Web)的适配的开发效率。

通常Web页面相比移动端UI更为复杂,所以本文集中探讨将UI Design转化为Web代码的方法。

Design to Code的自动化方法有多年的探索,大致可以划分为几种

  • 基于规则的方法:从特定格式的设计稿,如Figma,Sketch、Adobe XDsketch等,转化为前端代码。或是由低代码平台,将拖拽组件生成的UI自动转化为前端代码。

  • 基于AI的方法:基于AI的方法有基于传统的CV方法,对设计稿中的视觉元素进行分类识别。近些年随着多模态大模型的发展,已可以实现图片转文本等能力,于是在design to code领域也有新的发展。

基于规则的Design to Code

TeleportHQ(https://teleporthq.io/) 是一款功能强大的低代码前端设计与开发平台,它提供了提供直观的拖拽式网站构建器,用户可简单地将元素拖放到页面上,快速搭建网页布局,无需复杂的代码编写。
在将用户构建的网站转化为code时,TeleportHQ首先会将包含有布局、样式的设计信息转换为一种通用的UIDL语言,这种语言采用类似下述的Json格式,来存储元素、样式等信息。

{
  "name": "Simple Component",
  "node": {
    "type": "element",
    "content": {
      "elementType": "container",
      "children": [
        {
          "type": "element",
          "content": {
            "elementType": "text",
            "style": {
              "margin": {
                "type": "static",
                "content": "10px"
              },
              "color": {
                "type": "static",
                "content": "red"
              }
            },
            "children": [
              {
                "type": "static",
                "content": "World!"
              }
            ]
          }
        }
      ]
    }
  }
}

之后,TeleportHQ会根据UIDL,生成Html5+css,也能自动生成适用于多种 JavaScript 框架的代码,如 React、Next、Vue、Nuxt、Angular 等。这个生成代码的过程是递归遍历UIDL中的每个UI元素,根据编写好的规则,生成每个元素对应的框架代码。这个代码生成器已开源到github,可以供用户进行二次开发或扩展。(https://github.com/teleporthq/teleport-code-generators

同时,TeleportHQ也提供了基于Figma的Design to code插件,可以将Figma的设计转化为代码。其基本的转换过程是,先将Figma的设计转化为TeleportHQ的UIDL,同时支持在TeleportHQ的可视化编辑器中进行调整修改,之后再转化为相应的代码。

例如,从Figma导出设计稿到TeleportHQ中

file

从TeleportHQ导出Html
file

跟TeleportHQ类似的Design to code插件还有Anima(https://www.animaapp.com/),也可以将Figma插件转化为code。
基于规则的Design to code方法,依赖输入的设计稿包含完整的布局与样式信息,转换方法比较直接,根据样式信息来做规则转化,转换出的代码相对准确。但依赖规则进行转换的局限性也比较大。

  • UI设计的工作,需要局限在特定的设计工具
  • 转换出的代码质量依赖设计质量,不能自动转化为响应式布局的代码

基于AI的Design to Code

基于规则的方法,非常简单直观,但适用的范围受限。如果我们希望结合AI生成图片的能力来做网页设计,再将图片交由AI转换为代码,基于规则的方法,就不太灵活。我们需要考虑更通用的方法,能将图片转换为代码。

基于传统机器学习算法实现

  • CV:淘宝开源的,ms sketch2code

  • 基于DL模型的pix2code

2017年Tony Beltramelli发表了一篇论文: pix2code: Generating Code from a Graphical User Interface Screenshoth,引起业界关注,论文使用深度学习技术将UI 截图识别生成 UI 结构描述,然后将 UI 结构描述转成 HTML 代码。这种方法实现了一个端到端模型,将设计稿图片转代码。作者将其工作开源到:https://github.com/tonybeltramelli/pix2code

模型结构

pix2code的模型借鉴了Image captioning的技术。Image captioning是输入一幅照片,输出一段文本描述照片中的内容。而design to code的过程,与其非常相似,同样是输入一幅照片,输入一段文本,而这段文本是我们想要的代码。
我们可以将这个过程拆分为3个子任务

  1. 理解图像的任务:根据输入的图片,推断出图片中的物体、身份、位置等信息(在这里则是按钮,图标,UI元素等信息)
  2. 理解语言的任务:可以理解语言并生成符合语法及语义的文本,在这里则是生成代码。
  3. 构建一个可以连接任务1和任务2的模型,将两者的能力结合起来,完成端到端的代码转换任务。

pix2code的模型结构如下:

file

pix2code的输入为UI图片以及context文本,输出为DSL语言,最后将DSL转换为多平台的前端代码,支持的前端平台包括iOS,Android和Web HTML。

DSL示例如下

file

  • 模型的训练:

在训练阶段,输入的GUI图片会通过一个基于CNN的视觉模型进行编码,生成向量p。context则通过一个具有多层LSTM的语言模型进行编码,生成向量qt。context是一个基于DSL的token序列,每个token是一个基于DSL词典的one-hot编码向量。

2个编码模型生成特征向量p和qt后,进行拼接,生成向量rt,输入给后续的解码模型,解码模型由多层LSTM网络构成。最后在softmax层,每次sample一个token作为输出,softmax层的大小与DSL的词典大小相同。

  • 模型的预测:

在预测阶段,输入的context的模型是上一次更新的token。模型最终输出的DSL文本序列,会通过一个基于规则的compiler将DSL转换为各个平台的前端代码。

  • 数据集:

pix2code的数据集,由iOS,Android,Web三个平台的数据构成。以Web数据集为例,全部数据集由1742对图片和DSL文件构成,这些数据属于合成数据,并非真实数据。

数据实例如下
|```

header {btn-inactive, btn-active, btn-inactive, btn-inactive, btn-inactive}row {double {small-title, text, btn-orange}double {small-title, text, btn-green}}row {single {small-title, text, btn-green}}row {quadruple {small-title, text, btn-green}quadruple {small-title, text, btn-green}quadruple {small-title, text, btn-orange}quadruple {small-title, text, btn-red}} file
  • 生成效果测试

在作者的论文中,对生成代码进行了效果测试,准确率可以达到77%

file

接下来我们在实际应用场景中进行测试,将下面的图片输入给训练好的pix2code,让其生成HTML代码

file

file


<html>
  <header>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<style>
.header{margin:20px 0}nav ul.nav-pills li{background-color:#333;border-radius:4px;margin-right:10px}.col-lg-3{width:24%;margin-right:1.333333%}.col-lg-6{width:49%;margin-right:2%}.col-lg-12,.col-lg-3,.col-lg-6{margin-bottom:20px;border-radius:6px;background-color:#f5f5f5;padding:20px}.row .col-lg-3:last-child,.row .col-lg-6:last-child{margin-right:0}footer{padding:20px 0;text-align:center;border-top:1px solid #bbb}
</style>
    <title>Scaffold</title>
  </header>
  <body>
    <main class="container">
      <div class="header clearfix">
  <nav>
    <ul class="nav nav-pills pull-left">
      <li><a href="#">Zsoiyo Oms</a></li>
<li class="active"><a href="#">Kvzzcl Lgw</a></li>
<li><a href="#">Ppbo Ocdif</a></li>
<li><a href="#">Xqlyxkm Ma</a></li>
<li><a href="#">Rppe Enobt</a></li>

    </ul>
  </nav>
</div>
<div class="row"><div class="col-lg-12">
<h4>Ssfhi</h4><p>eolld l alnrgmrxhadpsdak dcfudte x lsakvmu cxwlagnx qaaw</p>
<a class="btn btn-success" href="#" role="button">Ncjpmq Qbq</a>

</div>
</div>
<div class="row"><div class="col-lg-6">
<h4>Nmwga</h4><p>zkmgj cot facwccevzzrpbvszxf  txgrcdjiwixet i  kkpwaxeqq</p>
<a class="btn btn-success" href="#" role="button">Etban Nled</a>

</div>
<div class="col-lg-6">
<h4>Idkpc</h4><p>iostghxt pv  uzdoaa p  rohkzxttijgreknlolyp naumyhrpifso</p>
<a class="btn btn-success" href="#" role="button">Nbb Bbakmj</a>

</div>
</div>
<div class="row"><div class="col-lg-3">
<h4>Egwfm</h4><p>fi spqhdnsklxnnfhkerjekyt   tzhz y ccxtspygtighnkcilm fg</p>
<a class="btn btn-success" href="#" role="button">Zumelfy Yw</a>

</div>
<div class="col-lg-3">
<h4>Vppuz</h4><p>pb rwpcjyj hup nemtzh djwqt otsqsodsokyi ikivacon qvpqpg</p>
<a class="btn btn-success" href="#" role="button">Sznrqi Idm</a>

</div>
<div class="col-lg-3">
<h4>Ytqdc</h4><p>cdxc rfbkn qlcmxfiqu  sgsajvnjqcsf ymr wf ndnwdvlfugpxia</p>
<a class="btn btn-success" href="#" role="button">Qa Aorqvge</a>

</div>
<div class="col-lg-3">
<h4>Hldfo</h4><p>lhv ybey ztvr erxjqv qbqnyehyms uh tlixrqznlfsssfnze jzr</p>
<a class="btn btn-success" href="#" role="button">Lswb Bvxeb</a>

</div>
</div>
<div class="row"><div class="col-lg-12">
<h4>Gnudw</h4><p>cjnvscsvjl sbxbnbdtmrwms d rmmumnzskwhv qj qbxvpga ohtjb</p>
<a class="btn btn-success" href="#" role="button">Ihrkqxl Lx</a>

</div>
</div>
<div class="row"><div class="col-lg-6">
<h4>Kbuig</h4><p>avat ka nmdayn pynh xk inntfoaxjstpyuswe a lmwzjgthlhjew</p>
<a class="btn btn-success" href="#" role="button">Cjenvp Pqs</a>

</div>
<div class="col-lg-6">
<h4>Urxdq</h4><p>sflbx qloesavh mbiqozvu iayiqws kbsyrnyazzomdc ayunig jl</p>
<a class="btn btn-success" href="#" role="button">Zlhdww Wkv</a>

</div>
</div>

      <footer class="footer">
        <p>© Tony Beltramelli 2017</p>
      </footer>
    </main>
    <script src="js/jquery.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
  </body>
</html>

从结果来看,是非常的糟糕,看不出与原始页面有任何关系。Pix2code在paper中提及的准确率仅能说明在它特定的测试集上有效,在实际网页上效果非常差,无法用于实际工作。

pix2code目前主要还是作为一个研究项目开源,在实际应用中并不理想。这可能受限于训练数据偏少,也可能是由于使用的训练数据为合成数据,非实际数据,因而与在实际应用中的表现与测试结果相差很大。

基于多模态LLM的实现

随着大语言模型的能力越来越强,开始出现使用大模型来做design to code的转换工作。
目前的视觉LLM已经可以根据用户输入的图片和文字,回答文字结果,那么设计稿转代码的工作也是类似的,将设计稿图片输入到LLM,让模型根据指令,生成文字序列(code)
开源软件screenshot-to-code(https://github.com/abi/screenshot-to-code),通过编写prompt,利用多模态大模型来实现,例如,我们将下面的prompt以及图片输入给GPT-4o,会生成相应的网页代码

You are an expert CSS developer
You take screenshots of a reference web page from the user, and then build single page apps 
using CSS, HTML and JS.
You might also be given a screenshot(The second image) of a web page that you have already built, and asked to
update it to look more like the reference image(The first image).

- Make sure the app looks exactly like the screenshot.
- Pay close attention to background color, text color, font size, font family, 
padding, margin, border, etc. Match the colors and sizes exactly.
- Use the exact text from the screenshot.
- Do not add comments in the code such as "<!-- Add other navigation links as needed -->" and "<!-- ... other news items ... -->" in place of writing the full code. WRITE THE FULL CODE.
- Repeat elements as needed to match the screenshot. For example, if there are 15 items, the code should have 15 items. DO NOT LEAVE comments like "<!-- Repeat for each news item -->" or bad things will happen.
- For images, use placeholder images from https://placehold.co and include a detailed description of the image in the alt text so that an image generation AI can generate the image later.

In terms of libraries,

- You can use Google Fonts
- Font Awesome for icons: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"></link>

Return only the full code in <html></html> tags.
Do not include markdown "```" or "```html" at the start or end.

file

  • 与LLM交互的Prompt示例如下
{
    "prompt": [
        {
            "role": "system",
            "content": "\nYou are an expert CSS developer\nYou take screenshots of a reference web page from the user, and then build single page apps \nusing CSS, HTML and JS.\nYou might also be given a screenshot(The second image) of a web page that you have already built, and asked to\nupdate it to look more like the reference image(The first image).\n\n- Make sure the app looks exactly like the screenshot.\n- Pay close attention to background color, text color, font size, font family, \npadding, margin, border, etc. Match the colors and sizes exactly.\n- Use the exact text from the screenshot.\n- Do not add comments in the code such as \"<!-- Add other navigation links as needed -->\" and \"<!-- ... other news items ... -->\" in place of writing the full code. WRITE THE FULL CODE.\n- Repeat elements as needed to match the screenshot. For example, if there are 15 items, the code should have 15 items. DO NOT LEAVE comments like \"<!-- Repeat for each news item -->\" or bad things will happen.\n- For images, use placeholder images from https://placehold.co and include a detailed description of the image in the alt text so that an image generation AI can generate the image later.\n\nIn terms of libraries,\n\n- You can use Google Fonts\n- Font Awesome for icons: <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css\"></link>\n\nReturn only the full code in <html></html> tags.\nDo not include markdown \"```\" or \"```html\" at the start or end.\n"
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "data:image/png;base64,iVBORw0KGgoAAAAN...",
                        "detail": "high"
                    }
                },
                {
                    "type": "text",
                    "text": "\nGenerate code for a web page that looks exactly like this.\n"
                }
            ]
        }
    ],
    "completion": "<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n ..."
}
  • GPT-4o生成的HTML网页效果如下:

file

<html lang="en">
 <head>
  <meta charset="utf-8"/>
  <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
  <title>
   TeleportHQ
  </title>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet"/>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet"/>
  <style>
   body {
            font-family: 'Inter', sans-serif;
            margin: 0;
            padding: 0;
            background-color: #ffffff;
        }
        .navbar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 40px;
            border-bottom: 1px solid #eaeaea;
        }
        .navbar .logo {
            display: flex;
            align-items: center;
        }
        .navbar .logo img {
            height: 24px;
            margin-right: 8px;
        }
        .navbar .menu {
            display: flex;
            align-items: center;
        }
        .navbar .menu a {
            margin: 0 15px;
            text-decoration: none;
            color: #000;
            font-weight: 500;
        }
        .navbar .menu a.new {
            background-color: #e0d7ff;
            color: #6b47dc;
            padding: 2px 6px;
            border-radius: 4px;
            font-size: 12px;
            margin-left: 5px;
        }
        .navbar .menu .cta {
            background-color: #6b47dc;
            color: #fff;
            padding: 10px 20px;
            border-radius: 5px;
            text-decoration: none;
            margin-left: 20px;
        }
        .content {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 60px 40px;
        }
        .content .text {
            max-width: 500px;
        }
        .content .text h1 {
            font-size: 48px;
            font-weight: 700;
            margin: 0 0 20px;
            line-height: 1.2;
        }
        .content .text p {
            font-size: 18px;
            line-height: 1.6;
            margin: 0 0 20px;
        }
        .content .text .cta {
            background-color: #000;
            color: #fff;
            padding: 15px 30px;
            border-radius: 5px;
            text-decoration: none;
            font-weight: 700;
        }
        .content .image {
            position: relative;
            width: 600px;
            height: 400px;
        }
        .content .image img {
            position: absolute;
            width: 100%;
            height: 100%;
            object-fit: cover;
        }
  </style>
 </head>
 <body>
  <div class="navbar">
   <div class="logo">
    <img alt="TeleportHQ logo with colorful abstract shapes" src="https://placehold.co/24x24"/>
    <span>
     teleport
     <span style="font-size: 10px;">
      HQ
     </span>
    </span>
   </div>
   <div class="menu">
    <a href="#">
     Product
    </a>
    <a class="new" href="#">
     New
    </a>
    <a href="#">
     Services
    </a>
    <a href="#">
     Resources
    </a>
    <a href="#">
     White Label Editor
    </a>
    <a href="#">
     Pricing
    </a>
    <a href="#">
     Login
    </a>
    <a class="cta" href="#">
     Start for free
    </a>
   </div>
  </div>
  <div class="content">
   <div class="text">
    <h1>
     Translate design to code in an automated way
    </h1>
    <p>
     TeleportHQ is a design-to-code tool that helps you build products faster and turn them into HTML.
    </p>
    <p>
     With our platform, you don’t need to write code, but developers can create a fully functional website or app based on a Figma design, which they can export as clean code.
    </p>
    <a class="cta" href="#">
     Start building
    </a>
   </div>
   <div class="image">
    <img alt="Screenshot of a design tool interface with various UI elements and code editor" src="https://placehold.co/600x400"/>
   </div>
  </div>
 </body>
</html>

生成的效果还是非常不错的,图片中的文字、导航菜单、按钮等元素识别基本准确,整体结构基本正确。并且可以识别出导航栏的阴影细节。但我们也可以看到有一些不完美的地方,如导航栏的login按钮被识别为了菜单项,"Start Building"按钮的圆角样式也没有复原出来,需要后期人工调整。

按照screenshot-to-code的评估,Claude Sonnet 3.7是它所支持的模型中表现最好的,我们再尝试使用claude重新生成一下这个页面。

file

<html>
 <head>
  <meta charset="utf-8"/>
  <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
  <title>
   TeleportHQ - Design to Code
  </title>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet"/>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"/>
  <style>
   * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Inter', sans-serif;
        }

        body {
            background-color: #ffffff;
        }

        .navbar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 80px;
            background-color: #ffffff;
        }

        .logo {
            display: flex;
            align-items: center;
        }

        .logo img {
            height: 40px;
        }

        .nav-links {
            display: flex;
            align-items: center;
            gap: 30px;
        }

        .nav-item {
            font-size: 16px;
            font-weight: 500;
            color: #333;
            text-decoration: none;
            display: flex;
            align-items: center;
        }

        .nav-item i {
            margin-left: 5px;
        }

        .new-badge {
            background-color: #7c4dff;
            color: white;
            font-size: 12px;
            padding: 2px 6px;
            border-radius: 4px;
            margin-right: 8px;
        }

        .login-btn {
            background-color: #e6e6e6;
            color: #333;
            padding: 12px 24px;
            border-radius: 6px;
            text-decoration: none;
            font-weight: 500;
            margin-right: 10px;
        }

        .start-btn {
            background-color: #7c4dff;
            color: white;
            padding: 12px 24px;
            border-radius: 6px;
            text-decoration: none;
            font-weight: 500;
        }

        .hero-section {
            display: flex;
            padding: 40px 80px;
            align-items: center;
            justify-content: space-between;
        }

        .hero-content {
            max-width: 600px;
        }

        .hero-title {
            font-size: 60px;
            font-weight: 700;
            line-height: 1.1;
            margin-bottom: 30px;
            color: #111;
        }

        .hero-description {
            font-size: 18px;
            line-height: 1.6;
            color: #444;
            margin-bottom: 30px;
        }

        .hero-image {
            max-width: 650px;
            position: relative;
        }

        .hero-image img {
            width: 100%;
            border-radius: 8px;
        }

        .start-building-btn {
            background-color: #111;
            color: white;
            padding: 16px 32px;
            border-radius: 50px;
            text-decoration: none;
            font-weight: 500;
            font-size: 18px;
            display: inline-block;
        }

        .built-badge {
            position: absolute;
            bottom: 20px;
            right: 20px;
            background-color: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 10px 20px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .built-badge img {
            width: 24px;
            height: 24px;
        }

        .pink-blob {
            position: absolute;
            top: -100px;
            right: -100px;
            width: 500px;
            height: 500px;
            background: radial-gradient(circle, rgba(255,0,255,0.5) 0%, rgba(255,0,255,0) 70%);
            border-radius: 50%;
            z-index: -1;
        }
  </style>
 </head>
 <body>
  <nav class="navbar">
   <div class="logo">
    <img alt="TeleportHQ logo with colorful geometric shapes and the text 'teleport HQ'" src="https://placehold.co/200x50/7c4dff/ffffff?text=teleportHQ"/>
   </div>
   <div class="nav-links">
    <a class="nav-item" href="#">
     Product
     <i class="fas fa-chevron-down">
     </i>
    </a>
    <a class="nav-item" href="#">
     <span class="new-badge">
      NEW
     </span>
     Services
     <i class="fas fa-chevron-down">
     </i>
    </a>
    <a class="nav-item" href="#">
     Resources
     <i class="fas fa-chevron-down">
     </i>
    </a>
    <a class="nav-item" href="#">
     White Label Editor
    </a>
    <a class="nav-item" href="#">
     Pricing
    </a>
    <a class="login-btn" href="#">
     Login
    </a>
    <a class="start-btn" href="#">
     Start for free
    </a>
   </div>
  </nav>
  <div class="hero-section">
   <div class="hero-content">
    <h1 class="hero-title">
     Translate design to code in an automated way
    </h1>
    <p class="hero-description">
     TeleportHQ is a design-to-code tool that helps you build products faster and turn them into HTML.
    </p>
    <p class="hero-description">
     With our platform, you don't need to write code, but developers can create a fully functional website or app based on a Figma design, which they can export as clean code.
    </p>
    <a class="start-building-btn" href="#">
     Start building
    </a>
   </div>
   <div class="hero-image">
    <div class="pink-blob">
    </div>
    <img alt="TeleportHQ interface showing a design-to-code conversion with a headphones website design on the right and code editor on the left, featuring blue headphones and CSS code" src="https://placehold.co/650x550/333/ffffff?text=TeleportHQ+Interface"/>
    <div class="built-badge">
     <img alt="TeleportHQ icon" src="https://placehold.co/24x24/ffffff/7c4dff?text=T"/>
     Built in TeleportHQ
    </div>
   </div>
  </div>
 </body>
</html>

claude生成页面的效果可以用惊艳来形容,导航栏的细节被完美还原,按钮的圆角样式也与原图保持一致,甚至尝试复原右侧背景。需要后期人工调整的工作非常少了。

接下来我们尝试一个更有挑战的复杂页面,这个页面包含有非常多的UI元素,各种卡片的样式也非常多样。我们让大模型来尝试做HTML的转换工作

file

  • GPT-4o生成的页面

file

<html lang="en">
 <head>
  <meta charset="utf-8"/>
  <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
  <title>
   Web Page
  </title>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet"/>
  <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;700&display=swap" rel="stylesheet"/>
  <style>
   body {
            margin: 0;
            font-family: 'Noto Sans SC', sans-serif;
            background-color: #f5f5f5;
        }
        .header {
            background-image: url('https://placehold.co/1920x300?text=Mountain+Sunset+Background');
            background-size: cover;
            background-position: center;
            padding: 20px;
            color: white;
        }
        .header .search-bar {
            display: flex;
            justify-content: center;
            margin-top: 20px;
        }
        .header input[type="text"] {
            width: 50%;
            padding: 10px;
            border-radius: 20px;
            border: none;
            font-size: 16px;
        }
        .header .icons {
            display: flex;
            justify-content: center;
            margin-top: 20px;
        }
        .header .icons i {
            margin: 0 10px;
            font-size: 24px;
        }
        .content {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            padding: 20px;
        }
        .card {
            background-color: white;
            border-radius: 10px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            margin: 10px;
            overflow: hidden;
            width: 300px;
        }
        .card img {
            width: 100%;
            height: auto;
        }
        .card-content {
            padding: 15px;
        }
        .card-content h3 {
            margin: 0;
            font-size: 18px;
            color: #333;
        }
        .card-content p {
            margin: 10px 0;
            color: #666;
        }
        .card-content .actions {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .card-content .actions i {
            color: #999;
        }
        .card-content .actions span {
            color: #999;
            font-size: 14px;
        }
  </style>
 </head>
 <body>
  <div class="header">
   <div class="search-bar">
    <input placeholder="搜索工作和网页" type="text"/>
   </div>
   <div class="icons">
    <i class="fab fa-microsoft">
    </i>
    <i class="fab fa-kickstarter">
    </i>
    <i class="fab fa-jira">
    </i>
    <i class="fab fa-google">
    </i>
    <i class="fab fa-facebook">
    </i>
    <i class="fab fa-twitter">
    </i>
    <i class="fas fa-plus">
    </i>
   </div>
  </div>
  <div class="content">
   <div class="card">
    <img alt="Game Advertisement" src="https://placehold.co/300x150?text=Game+Advertisement"/>
    <div class="card-content">
     <h3>
      散人都能爽玩!
     </h3>
     <p>
      新版本上线,快来体验!
     </p>
     <div class="actions">
      <i class="fas fa-heart">
      </i>
      <span>
       16
      </span>
     </div>
    </div>
   </div>
   <div class="card">
    <img alt="News Image" src="https://placehold.co/300x150?text=News+Image"/>
    <div class="card-content">
     <h3>
      刚刚,成龙发文!
     </h3>
     <p>
      关注热点,了解更多。
     </p>
     <div class="actions">
      <i class="fas fa-heart">
      </i>
      <span>
       7
      </span>
     </div>
    </div>
   </div>
   <div class="card">
    <img alt="Map Image" src="https://placehold.co/300x150?text=Map+Image"/>
    <div class="card-content">
     <h3>
      交通拥堵
     </h3>
     <p>
      实时路况,提前规划。
     </p>
     <div class="actions">
      <i class="fas fa-heart">
      </i>
      <span>
       41
      </span>
     </div>
    </div>
   </div>
   <div class="card">
    <img alt="Weather Image" src="https://placehold.co/300x150?text=Weather+Image"/>
    <div class="card-content">
     <h3>
      北京 -1°C
     </h3>
     <p>
      天气预报,及时了解。
     </p>
     <div class="actions">
      <i class="fas fa-heart">
      </i>
      <span>
       23
      </span>
     </div>
    </div>
   </div>
   <div class="card">
    <img alt="Food Image" src="https://placehold.co/300x150?text=Food+Image"/>
    <div class="card-content">
     <h3>
      营养还是蒸的好!
     </h3>
     <p>
      推荐5道蒸菜做法,清单健康不上火。
     </p>
     <div class="actions">
      <i class="fas fa-heart">
      </i>
      <span>
       6
      </span>
     </div>
    </div>
   </div>
   <div class="card">
    <img alt="Technology Image" src="https://placehold.co/300x150?text=Technology+Image"/>
    <div class="card-content">
     <h3>
      这还咋呼?华为Pura 80 Ultra配置曝光,写着“高通”俩字
     </h3>
     <p>
      最新科技资讯,了解更多。
     </p>
     <div class="actions">
      <i class="fas fa-heart">
      </i>
      <span>
       14
      </span>
     </div>
    </div>
   </div>
   <div class="card">
    <img alt="Car Image" src="https://placehold.co/300x150?text=Car+Image"/>
    <div class="card-content">
     <h3>
      A、B、C、D级车是什么鬼?这次给你讲清楚
     </h3>
     <p>
      汽车知识,轻松掌握。
     </p>
     <div class="actions">
      <i class="fas fa-heart">
      </i>
      <span>
       9
      </span>
     </div>
    </div>
   </div>
   <div class="card">
    <img alt="Earth Image" src="https://placehold.co/300x150?text=Earth+Image"/>
    <div class="card-content">
     <h3>
      地球在宇宙中的详细地址,到底藏在这颗“蓝色星球”在哪里?
     </h3>
     <p>
      探索宇宙,了解地球。
     </p>
     <div class="actions">
      <i class="fas fa-heart">
      </i>
      <span>
       8
      </span>
     </div>
    </div>
   </div>
  </div>
 </body>
</html>

这次GPT-4o生成的网页与原图相差甚远,仅有少量的UI元素,如搜索框,被正确地识别出来,整体结构也与原图差别很大,在复杂UI的生成方面,无法达到实用的效果。

我们再来看下Claude生成的结果

file

<html>
 <head>
  <meta charset="utf-8"/>
  <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
  <title>
   MSN China
  </title>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet"/>
  <style>
   * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Microsoft YaHei', Arial, sans-serif;
        }

        body {
            background-image: url('https://placehold.co/1920x1080/007bff/ffffff?text=Sunset+Mountain+Background');
            background-size: cover;
            background-position: center;
            background-attachment: fixed;
            color: #333;
        }

        .top-bar {
            display: flex;
            justify-content: flex-end;
            align-items: center;
            padding: 10px 20px;
            color: white;
        }

        .top-bar .city {
            margin-right: 10px;
        }

        .top-bar .temp {
            margin-right: 10px;
            display: flex;
            align-items: center;
        }

        .top-bar .temp i {
            color: #f8c01d;
            margin-right: 5px;
        }

        .top-bar .settings {
            margin-left: 10px;
        }

        .search-container {
            display: flex;
            justify-content: center;
            margin: 20px 0;
        }

        .search-box {
            display: flex;
            width: 60%;
            max-width: 600px;
        }

        .search-input {
            flex: 1;
            padding: 10px 15px;
            border: none;
            border-radius: 20px 0 0 20px;
            outline: none;
            font-size: 14px;
        }

        .search-button {
            background-color: #0078d4;
            color: white;
            border: none;
            border-radius: 0 20px 20px 0;
            padding: 0 15px;
            cursor: pointer;
        }

        .app-icons {
            display: flex;
            justify-content: center;
            margin: 20px 0;
        }

        .app-icon {
            display: flex;
            flex-direction: column;
            align-items: center;
            margin: 0 10px;
            color: white;
            text-decoration: none;
            font-size: 12px;
        }

        .icon-circle {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            margin-bottom: 5px;
        }

        .blue-bg {
            background-color: #0078d4;
        }

        .black-bg {
            background-color: #000;
        }

        .red-bg {
            background-color: #e62117;
        }

        .orange-bg {
            background-color: #ff6700;
        }

        .green-bg {
            background-color: #00a651;
        }

        .gray-bg {
            background-color: #767676;
        }

        .teal-bg {
            background-color: #00a99d;
        }

        .add-bg {
            background-color: rgba(255, 255, 255, 0.2);
        }

        .quick-links {
            display: flex;
            justify-content: center;
            margin: 20px 0;
            flex-wrap: wrap;
        }

        .quick-link {
            display: flex;
            align-items: center;
            margin: 0 10px;
            color: white;
            text-decoration: none;
            font-size: 14px;
            background-color: rgba(0, 0, 0, 0.5);
            padding: 5px 15px;
            border-radius: 20px;
            margin-bottom: 10px;
        }

        .quick-link i {
            margin-right: 5px;
        }

        .content-container {
            background-color: white;
            margin: 0 auto;
            max-width: 1200px;
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }

        .nav-tabs {
            display: flex;
            background-color: #f8f8f8;
            border-bottom: 1px solid #ddd;
            padding: 0 20px;
        }

        .nav-tab {
            padding: 10px 15px;
            cursor: pointer;
            font-size: 14px;
            color: #666;
        }

        .nav-tab.active {
            color: #0078d4;
            border-bottom: 2px solid #0078d4;
        }

        .content-grid {
            display: grid;
            grid-template-columns: repeat(12, 1fr);
            gap: 15px;
            padding: 15px;
        }

        .card {
            background-color: white;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
            position: relative;
        }

        .card-large {
            grid-column: span 6;
            grid-row: span 2;
        }

        .card-medium {
            grid-column: span 3;
            grid-row: span 2;
        }

        .card-small {
            grid-column: span 3;
            grid-row: span 1;
        }

        .card-image {
            width: 100%;
            height: 200px;
            object-fit: cover;
        }

        .card-large .card-image {
            height: 300px;
        }

        .card-content {
            padding: 10px;
        }

        .card-title {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 5px;
        }

        .card-source {
            font-size: 12px;
            color: #666;
            display: flex;
            align-items: center;
            margin-bottom: 5px;
        }

        .card-source img {
            width: 16px;
            height: 16px;
            border-radius: 50%;
            margin-right: 5px;
        }

        .card-time {
            font-size: 12px;
            color: #999;
            margin-left: 5px;
        }

        .card-actions {
            display: flex;
            justify-content: space-between;
            padding: 5px 10px;
            color: #666;
            font-size: 12px;
        }

        .card-action {
            display: flex;
            align-items: center;
        }

        .card-action i {
            margin-right: 3px;
        }

        .news-list {
            grid-column: span 3;
            display: flex;
            flex-direction: column;
        }

        .news-item {
            display: flex;
            align-items: center;
            padding: 10px;
            border-bottom: 1px solid #eee;
        }

        .news-number {
            color: #ff6700;
            font-weight: bold;
            margin-right: 10px;
            min-width: 15px;
        }

        .news-title {
            font-size: 14px;
            flex: 1;
        }

        .weather-card {
            background-color: #0078d4;
            color: white;
            padding: 15px;
        }

        .weather-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 10px;
        }

        .weather-temp {
            font-size: 36px;
            font-weight: bold;
            display: flex;
            align-items: center;
        }

        .weather-icon {
            font-size: 24px;
            margin-right: 5px;
            color: #f8c01d;
        }

        .weather-forecast {
            display: flex;
            justify-content: space-between;
            margin-top: 15px;
        }

        .forecast-day {
            display: flex;
            flex-direction: column;
            align-items: center;
            font-size: 12px;
        }

        .stock-card {
            padding: 15px;
        }

        .stock-item {
            display: flex;
            justify-content: space-between;
            padding: 8px 0;
            border-bottom: 1px solid #eee;
        }

        .stock-name {
            font-size: 14px;
        }

        .stock-price {
            font-size: 14px;
        }

        .stock-change {
            font-size: 12px;
            color: #ff4d4f;
            display: flex;
            align-items: center;
        }

        .stock-change.positive {
            color: #52c41a;
        }

        .calendar-card {
            padding: 15px;
        }

        .calendar-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 10px;
        }

        .calendar-date {
            font-size: 18px;
            font-weight: bold;
        }

        .calendar-grid {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 5px;
            margin-top: 10px;
        }

        .calendar-day {
            display: flex;
            flex-direction: column;
            align-items: center;
            font-size: 12px;
            padding: 5px;
        }

        .calendar-day.today {
            background-color: #0078d4;
            color: white;
            border-radius: 50%;
        }

        .ad-label {
            position: absolute;
            bottom: 5px;
            right: 5px;
            background-color: rgba(0, 0, 0, 0.5);
            color: white;
            font-size: 10px;
            padding: 2px 5px;
            border-radius: 2px;
        }

        .more-actions {
            display: flex;
            justify-content: center;
            margin: 10px 0;
        }

        .more-button {
            background-color: #f0f0f0;
            border: none;
            padding: 5px 15px;
            border-radius: 15px;
            margin: 0 5px;
            font-size: 12px;
            cursor: pointer;
        }

        .more-button i {
            margin-right: 5px;
        }

        .news-source-list {
            padding: 10px;
        }

        .news-source-item {
            display: flex;
            align-items: center;
            padding: 8px 0;
            border-bottom: 1px solid #eee;
        }

        .news-source-icon {
            width: 24px;
            height: 24px;
            border-radius: 50%;
            margin-right: 10px;
            background-color: #f0f0f0;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .news-source-name {
            font-size: 14px;
            flex: 1;
        }

        .add-button {
            color: #999;
            cursor: pointer;
        }

        .traffic-map {
            height: 150px;
            background-color: #f0f0f0;
            position: relative;
        }

        .traffic-info {
            position: absolute;
            bottom: 10px;
            left: 10px;
            background-color: white;
            padding: 5px 10px;
            border-radius: 5px;
            font-size: 12px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
        }

        .traffic-time {
            color: #ff6700;
            font-weight: bold;
            font-size: 16px;
        }

        .game-ad {
            position: relative;
        }

        .game-title {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;
            font-size: 36px;
            font-weight: bold;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
        }

        .game-subtitle {
            position: absolute;
            top: 60%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;
            font-size: 18px;
            text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
        }

        .custom-tabs {
            display: flex;
            margin-bottom: 10px;
        }

        .custom-tab {
            padding: 5px 10px;
            font-size: 12px;
            cursor: pointer;
        }

        .custom-tab.active {
            border-bottom: 2px solid #0078d4;
            color: #0078d4;
        }

        .ellipsis {
            text-overflow: ellipsis;
            white-space: nowrap;
            overflow: hidden;
        }
  </style>
 </head>
 <body>
  <div class="top-bar">
   <div class="city">
    北京市
   </div>
   <div class="temp">
    <i class="fas fa-sun">
    </i>
    -1°C
   </div>
   <div class="settings">
    <i class="fas fa-cog">
    </i>
   </div>
  </div>
  <div class="search-container">
   <div class="search-box">
    <input class="search-input" placeholder="搜索工作和网页" type="text"/>
    <button class="search-button">
     <i class="fas fa-search">
     </i>
    </button>
   </div>
  </div>
  <div class="app-icons">
   <a class="app-icon" href="#">
    <div class="icon-circle blue-bg">
     <i class="fab fa-edge">
     </i>
    </div>
    <span>
     Microsoft Edge
    </span>
   </a>
   <a class="app-icon" href="#">
    <div class="icon-circle black-bg">
     <i class="fab fa-xbox">
     </i>
    </div>
    <span>
     Xbox
    </span>
   </a>
   <a class="app-icon" href="#">
    <div class="icon-circle red-bg">
     <i class="fas fa-shopping-bag">
     </i>
    </div>
    <span>
     京东
    </span>
   </a>
   <a class="app-icon" href="#">
    <div class="icon-circle orange-bg">
     <i class="fas fa-user">
     </i>
    </div>
    <span>
     淘宝
    </span>
   </a>
   <a class="app-icon" href="#">
    <div class="icon-circle green-bg">
     <i class="fas fa-comment">
     </i>
    </div>
    <span>
     微信公众号
    </span>
   </a>
   <a class="app-icon" href="#">
    <div class="icon-circle gray-bg">
     <i class="fas fa-file">
     </i>
    </div>
    <span>
     Microsoft 365
    </span>
   </a>
   <a class="app-icon" href="#">
    <div class="icon-circle teal-bg">
     <i class="fas fa-cloud">
     </i>
    </div>
    <span>
     微软云服务平台
    </span>
   </a>
   <a class="app-icon" href="#">
    <div class="icon-circle add-bg">
     <i class="fas fa-plus">
     </i>
    </div>
    <span>
     添加应用
    </span>
   </a>
  </div>
  <div class="quick-links">
   <a class="quick-link" href="#">
    <i class="fas fa-search">
    </i>
    <span>
     必应搜索
    </span>
   </a>
   <a class="quick-link" href="#">
    <i class="fas fa-music">
    </i>
    <span>
     抖音
    </span>
   </a>
   <a class="quick-link" href="#">
    <i class="fas fa-shopping-cart">
    </i>
    <span>
     京东
    </span>
   </a>
   <a class="quick-link" href="#">
    <i class="fas fa-video">
    </i>
    <span>
     哔哩
    </span>
   </a>
   <a class="quick-link" href="#">
    <i class="fas fa-gamepad">
    </i>
    <span>
     5177游戏
    </span>
   </a>
   <a class="quick-link" href="#">
    <i class="fas fa-cloud">
    </i>
    <span>
     智慧内容
    </span>
   </a>
   <a class="quick-link" href="#">
    <i class="fas fa-map-marker-alt">
    </i>
    <span>
     美团外卖
    </span>
   </a>
   <a class="quick-link" href="#">
    <i class="fas fa-ellipsis-h">
    </i>
    <span>
     更多
    </span>
   </a>
  </div>
  <div class="content-container">
   <div class="nav-tabs">
    <div class="nav-tab active">
     <img alt="MSN Logo" src="https://placehold.co/20x20/0078d4/ffffff?text=MSN" style="width: 20px; height: 20px; margin-right: 5px;"/>
     首页
    </div>
    <div class="nav-tab">
     热点
    </div>
    <div class="nav-tab">
     财经
    </div>
    <div class="nav-tab">
     体育
    </div>
    <div class="nav-tab">
     娱乐
    </div>
    <div class="nav-tab">
     天气
    </div>
    <div class="nav-tab">
     体育
    </div>
    <div class="nav-tab">
     小视频
    </div>
    <div class="nav-tab">
     财经
    </div>
    <div class="nav-tab">
     电视
    </div>
    <div class="nav-tab">
     购物
    </div>
    <div class="nav-tab">
     健康
    </div>
    <div class="nav-tab">
     交通
    </div>
    <div class="nav-tab">
     大众汽车
    </div>
    <div class="nav-tab">
     日历
    </div>
   </div>
   <div class="more-actions">
    <button class="more-button">
     <i class="fas fa-sync-alt">
     </i>
     更新内容
    </button>
    <button class="more-button">
     <i class="fas fa-cog">
     </i>
     个性化设置
    </button>
   </div>
   <div class="content-grid">
    <!-- Game Ad Card -->
    <div class="card card-large game-ad">
     <img alt="传奇游戏广告展示古代中国风格的游戏场景,展示了宫殿和角色" class="card-image" src="https://placehold.co/600x300/ff6700/ffffff?text=传奇游戏广告"/>
     <div class="game-title">
      传奇3
     </div>
     <div class="game-subtitle">
      全新2025版本
     </div>
     <div class="card-content">
      <div class="card-source">
       <img alt="游戏图标" src="https://placehold.co/16x16/ff6700/ffffff?text=游戏"/>
       <span>
        官方推荐·新游推荐
       </span>
      </div>
      <div class="card-title">
       散人都能爽玩!
      </div>
     </div>
     <div class="ad-label">
      广告
     </div>
    </div>
    <!-- News Source List -->
    <div class="card news-list">
     <div style="padding: 10px; display: flex; justify-content: space-between; align-items: center;">
      <span style="font-weight: bold;">
       为你推荐
      </span>
      <i class="fas fa-ellipsis-h">
      </i>
     </div>
     <div class="news-source-list">
      <div class="news-source-item">
       <div class="news-source-icon" style="background-color: #e62117; color: white;">
        新
       </div>
       <div class="news-source-name">
        新华社
       </div>
       <div class="add-button">
        <i class="fas fa-plus">
        </i>
       </div>
      </div>
      <div class="news-source-item">
       <div class="news-source-icon" style="background-color: #ff6700; color: white;">
        人
       </div>
       <div class="news-source-name">
        人民网
       </div>
       <div class="add-button">
        <i class="fas fa-plus">
        </i>
       </div>
      </div>
      <div class="news-source-item">
       <div class="news-source-icon" style="background-color: #0078d4; color: white;">
        日
       </div>
       <div class="news-source-name">
        每日经济新闻
       </div>
       <div class="add-button">
        <i class="fas fa-plus">
        </i>
       </div>
      </div>
      <div class="news-source-item">
       <div class="news-source-icon" style="background-color: #52c41a; color: white;">
        生
       </div>
       <div class="news-source-name">
        生活小课堂
       </div>
       <div class="add-button">
        <i class="fas fa-plus">
        </i>
       </div>
      </div>
      <div class="news-source-item">
       <div class="news-source-icon" style="background-color: #e62117; color: white;">
        IT
       </div>
       <div class="news-source-name">
        IT之家
       </div>
       <div class="add-button">
        <i class="fas fa-plus">
        </i>
       </div>
      </div>
     </div>
     <div style="padding: 10px; text-align: center; color: #0078d4; font-size: 12px;">
      <i class="fas fa-cog">
      </i>
      个性化资讯推荐
     </div>
    </div>
    <!-- News Card -->
    <div class="card card-medium">
     <img alt="水滴特写镜头,展示水滴的晶莹剔透和光影效果" class="card-image" src="https://placehold.co/400x200/0078d4/ffffff?text=水滴特写"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="人民网图标" src="https://placehold.co/16x16/ff6700/ffffff?text=人民"/>
       <span>
        人民网网
       </span>
       <span class="card-time">
        · 9小时
       </span>
      </div>
      <div class="card-title">
       0.1秒的水滴特写 治愈了12版
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       181
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- Food Recipe Card -->
    <div class="card card-medium">
     <img alt="一碗美味的肉丸,配有蔬菜和汤汁,看起来非常诱人" class="card-image" src="https://placehold.co/400x200/52c41a/ffffff?text=美食肉丸"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="美食频道图标" src="https://placehold.co/16x16/52c41a/ffffff?text=美食"/>
       <span>
        美食频道
       </span>
       <span class="card-time">
        · 17小时
       </span>
      </div>
      <div class="card-title">
       营养还是蒸的好!推荐5道蒸菜做法,清单健康不上火
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       7
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- City View Card -->
    <div class="card card-medium">
     <img alt="城市全景,展示了城市的天际线和周围的山脉" class="card-image" src="https://placehold.co/400x200/0078d4/ffffff?text=城市风景"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="旅游频道图标" src="https://placehold.co/16x16/0078d4/ffffff?text=旅游"/>
       <span>
        旅游频道
       </span>
       <span class="card-time">
        · 23小时
       </span>
      </div>
      <div class="card-title">
       重庆真把广州给PK掉了?
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       23
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- Game Ad Card -->
    <div class="card card-small">
     <img alt="游戏广告展示了一个肌肉发达的战士角色" class="card-image" src="https://placehold.co/400x200/e62117/ffffff?text=游戏广告"/>
     <div class="card-content">
      <div class="card-source">
       <span>
        传奇游戏
       </span>
      </div>
      <div class="card-title">
       2025传奇新版本
      </div>
     </div>
     <div class="ad-label">
      广告
     </div>
    </div>
    <!-- Weather Card -->
    <div class="card card-small weather-card">
     <div class="weather-header">
      <div>
       <i class="fas fa-map-marker-alt">
       </i>
       北京市
      </div>
      <div>
       预报
      </div>
     </div>
     <div class="weather-temp">
      <i class="weather-icon fas fa-moon">
      </i>
      -1°C
     </div>
     <div>
      预报信息
     </div>
     <div class="weather-forecast">
      <div class="forecast-day">
       <div>
        今天
       </div>
       <i class="fas fa-sun" style="color: #f8c01d;">
       </i>
       <div>
        0°
       </div>
      </div>
      <div class="forecast-day">
       <div>
        周五
       </div>
       <i class="fas fa-cloud-sun" style="color: #f8c01d;">
       </i>
       <div>
        5°
       </div>
      </div>
      <div class="forecast-day">
       <div>
        周六
       </div>
       <i class="fas fa-cloud" style="color: #f8c01d;">
       </i>
       <div>
        6°
       </div>
      </div>
      <div class="forecast-day">
       <div>
        周日
       </div>
       <i class="fas fa-cloud" style="color: #f8c01d;">
       </i>
       <div>
        8°
       </div>
      </div>
      <div class="forecast-day">
       <div>
        周一
       </div>
       <i class="fas fa-sun" style="color: #f8c01d;">
       </i>
       <div>
        10°
       </div>
      </div>
     </div>
     <div style="text-align: right; font-size: 12px; margin-top: 10px;">
      查看详细预报
     </div>
    </div>
    <!-- Hot News List -->
    <div class="card news-list">
     <div style="padding: 10px; display: flex; justify-content: space-between; align-items: center;">
      <span style="font-weight: bold; color: #ff6700;">
       热搜
      </span>
      <i class="fas fa-ellipsis-h">
      </i>
     </div>
     <div class="news-source-list">
      <div class="news-item">
       <div class="news-number">
        1
       </div>
       <div class="news-title">
        小米SU7过程时速最高限速?官方:不实
       </div>
      </div>
      <div class="news-item">
       <div class="news-number">
        2
       </div>
       <div class="news-title">
        苹果将推出iPhone最全面料
       </div>
      </div>
      <div class="news-item">
       <div class="news-number">
        3
       </div>
       <div class="news-title">
        《崩坏3》将全球公测!!首测TOP10
       </div>
      </div>
      <div class="news-item">
       <div class="news-number">
        4
       </div>
       <div class="news-title">
        国家统计局:1月CPI同比上涨0.5%
       </div>
      </div>
      <div class="news-item">
       <div class="news-number">
        5
       </div>
       <div class="news-title">
        数据显示中国影视房屋销售增长
       </div>
      </div>
      <div class="news-item">
       <div class="news-number">
        6
       </div>
       <div class="news-title">
        有人花1亿购买DeepSeek教育资源
       </div>
      </div>
     </div>
    </div>
    <!-- Bedroom Renovation Card -->
    <div class="card card-small">
     <img alt="一间精心装修的卧室,带有床、窗帘和温馨的灯光" class="card-image" src="https://placehold.co/400x200/f8c01d/ffffff?text=卧室装修"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="家居小课堂图标" src="https://placehold.co/16x16/f8c01d/ffffff?text=家居"/>
       <span>
        生活小课堂
       </span>
       <span class="card-time">
        · 3小时
       </span>
      </div>
      <div class="card-title">
       为什么睡觉多的人身材1.8米的床,改选1.5米的呢?
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       187
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- Stock Market Card -->
    <div class="card card-small stock-card">
     <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
      <span style="font-weight: bold;">
       市场
      </span>
      <i class="fas fa-ellipsis-h">
      </i>
     </div>
     <div class="stock-item">
      <div class="stock-name">
       上证指数
      </div>
      <div>
       <div class="stock-price">
        2,865.87
       </div>
       <div class="stock-change">
        +1.01%
       </div>
      </div>
     </div>
     <div class="stock-item">
      <div class="stock-name">
       深证成指
      </div>
      <div>
       <div class="stock-price">
        8,929.50
       </div>
       <div class="stock-change">
        +1.78%
       </div>
      </div>
     </div>
     <div class="stock-item">
      <div class="stock-name">
       创业板指
      </div>
      <div>
       <div class="stock-price">
        1,776.39
       </div>
       <div class="stock-change">
        +2.63%
       </div>
      </div>
     </div>
     <div class="stock-item">
      <div class="stock-name">
       USD/CNY
      </div>
      <div>
       <div class="stock-price">
        7.1984
       </div>
       <div class="stock-change positive">
        -0.00%
       </div>
      </div>
     </div>
     <div class="stock-item">
      <div class="stock-name">
       恒生指数
      </div>
      <div>
       <div class="stock-price">
        15,533.94
       </div>
       <div class="stock-change">
        -1.18%
       </div>
      </div>
     </div>
     <div style="text-align: right; font-size: 12px; color: #0078d4; margin-top: 10px;">
      查看更多
     </div>
    </div>
    <!-- Sports Card -->
    <div class="card card-small">
     <img alt="冬季运动员在雪地上滑雪,展示了精彩的运动瞬间" class="card-image" src="https://placehold.co/400x200/0078d4/ffffff?text=冬季运动"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="体育频道图标" src="https://placehold.co/16x16/0078d4/ffffff?text=体育"/>
       <span>
        体育频道
       </span>
       <span class="card-time">
        · 1小时
       </span>
      </div>
      <div class="card-title">
       退役韩国队组图揭秘,中国队摘铜,网友炸了!
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       2
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- Game Character Card -->
    <div class="card card-small">
     <img alt="游戏角色特写,展示了一个白胡子老人的面部特写" class="card-image" src="https://placehold.co/400x200/0078d4/ffffff?text=游戏角色"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="一点资讯图标" src="https://placehold.co/16x16/e62117/ffffff?text=游戏"/>
       <span>
        一点资讯
       </span>
       <span class="card-time">
        · 5小时
       </span>
      </div>
      <div class="card-title">
       《崩坏 2》无量仙人:好人还是坏人?深度剖析苏东坡色
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       976
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- American Airlines Card -->
    <div class="card card-small">
     <img alt="美国航空公司的飞机特写" class="card-image" src="https://placehold.co/400x200/767676/ffffff?text=美国航空"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="科技资讯图标" src="https://placehold.co/16x16/767676/ffffff?text=科技"/>
       <span>
        科技资讯
       </span>
       <span class="card-time">
        · 17小时
       </span>
      </div>
      <div class="card-title">
       这还行吗?华为Pura 80 Ultra配置曝光,专属"黑科"停字
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       14
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- Game Character Card -->
    <div class="card card-small">
     <img alt="游戏角色特写,展示了一个穿着华丽服装的女性角色" class="card-image" src="https://placehold.co/400x200/ff6700/ffffff?text=游戏角色"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="科技资讯图标" src="https://placehold.co/16x16/ff6700/ffffff?text=游戏"/>
       <span>
        科技资讯
       </span>
       <span class="card-time">
        · 1天
       </span>
      </div>
      <div class="card-title">
       《王者荣耀》西施COS:身穿古装,头戴花饰,气质绝美还原
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       143
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- American Airlines Card -->
    <div class="card card-small">
     <img alt="一辆黑色轿车的侧面特写" class="card-image" src="https://placehold.co/400x200/000000/ffffff?text=汽车"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="汽车频道图标" src="https://placehold.co/16x16/e62117/ffffff?text=汽车"/>
       <span>
        汽车频道
       </span>
       <span class="card-time">
        · 3天
       </span>
      </div>
      <div class="card-title">
       A、B、C、D级车是什么意思?这次总算明白了
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       212
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- Earth Card -->
    <div class="card card-small">
     <img alt="地球从太空中拍摄的照片,展示了蓝色的海洋和白色的云层" class="card-image" src="https://placehold.co/400x200/0078d4/ffffff?text=地球"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="一点资讯图标" src="https://placehold.co/16x16/0078d4/ffffff?text=科学"/>
       <span>
        一点资讯/科学
       </span>
       <span class="card-time">
        · 3天
       </span>
      </div>
      <div class="card-title">
       地球在宇宙的位置到底在哪里?我们是在中心还是边缘?
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       30
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- Hospital Card -->
    <div class="card card-small">
     <img alt="医院走廊,展示了医院的内部环境" class="card-image" src="https://placehold.co/400x200/52c41a/ffffff?text=医院"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="健康大学堂图标" src="https://placehold.co/16x16/52c41a/ffffff?text=健康"/>
       <span>
        健康大学堂
       </span>
      </div>
      <div class="card-title">
       入住27天,我发现这家医院服务态度很好,纯粹是"没有硬骨头"
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       129
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- Game Ad Card -->
    <div class="card card-small">
     <img alt="游戏广告展示了一个可爱的卡通角色" class="card-image" src="https://placehold.co/400x200/e62117/ffffff?text=游戏广告"/>
     <div class="card-content">
      <div class="card-source">
       <img alt="一点资讯图标" src="https://placehold.co/16x16/e62117/ffffff?text=游戏"/>
       <span>
        一点资讯
       </span>
       <span class="card-time">
        · 21小时
       </span>
      </div>
      <div class="card-title">
       《崩坏2:魔道篇》进入全球票房前60,国外影院一票难求
      </div>
     </div>
     <div class="card-actions">
      <div class="card-action">
       <i class="far fa-eye">
       </i>
       211
      </div>
      <div class="card-action">
       <i class="far fa-heart">
       </i>
      </div>
     </div>
    </div>
    <!-- American Airlines Card -->
    <div class="card card-small">
     <img alt="交通地图,展示了城市的道路和交通状况" class="card-image" src="https://placehold.co/400x200/0078d4/ffffff?text=交通地图"/>
     <div class="traffic-map">
      <div class="traffic-info">
       <div class="traffic-time">
        41
       </div>
       <div>
        中等流量
       </div>
       <div>
        昌平区 朝阳区
       </div>
      </div>
     </div>
     <div style="text-align: right; font-size: 12px; padding: 5px 10px;">
      在地图上查看
     </div>
    </div>
    <!-- Basketball League Card -->
    <div class="card card-small">
     <div style="padding: 10px; display: flex; justify-content: space-between; align-items: center;">
      <span style="font-weight: bold;">
       美国职业篮球联赛
      </span>
      <i class="fas fa-ellipsis-h">
      </i>
     </div>
     <div style="padding: 0 10px;">
      <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
       <div style="display: flex; align-items: center;">
        <img alt="篮球队标志" src="https://placehold.co/30x30/0078d4/ffffff?text=球队" style="width: 30px; height: 30px; margin-right: 10px;"/>
        <div>
         <div>
          勇士
         </div>
         <div style="font-size: 10px; color: #999;">
          西部
         </div>
        </div>
       </div>
       <div style="font-weight: bold; font-size: 18px;">
        110 - 130
       </div>
       <div style="display: flex; align-items: center;">
        <div style="text-align: right;">
         <div>
          湖人
         </div>
         <div style="font-size: 10px; color: #999;">
          西部
         </div>
        </div>
        <img alt="湖人队标志" src="https://placehold.co/30x30/552583/ffffff?text=湖人" style="width: 30px; height: 30px; margin-left: 10px;"/>
       </div>
      </div>
      <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
       <div style="display: flex; align-items: center;">
        <img alt="凯尔特人队标志" src="https://placehold.co/30x30/007a33/ffffff?text=凯尔" style="width: 30px; height: 30px; margin-right: 10px;"/>
        <div>
         <div>
          凯尔特人
         </div>
         <div style="font-size: 10px; color: #999;">
          东部
         </div>
        </div>
       </div>
       <div style="font-weight: bold; font-size: 18px;">
        118 - 123
       </div>
       <div style="display: flex; align-items: center;">
        <div style="text-align: right;">
         <div>
          篮网
         </div>
         <div style="font-size: 10px; color: #999;">
          东部
         </div>
        </div>
        <img alt="篮网队标志" src="https://placehold.co/30x30/000000/ffffff?text=篮网" style="width: 30px; height: 30px; margin-left: 10px;"/>
       </div>
      </div>
      <div style="display: flex; justify-content: space-between; align-items: center;">
       <div style="display: flex; align-items: center;">
        <img alt="火箭队标志" src="https://placehold.co/30x30/ce1141/ffffff?text=火箭" style="width: 30px; height: 30px; margin-right: 10px;"/>
        <div>
         <div>
          火箭
         </div>
         <div style="font-size: 10px; color: #999;">
          西部
         </div>
        </div>
       </div>
       <div style="font-weight: bold; font-size: 18px;">
        122 - 105
       </div>
       <div style="display: flex; align-items: center;">
        <div style="text-align: right;">
         <div>
          公牛
         </div>
         <div style="font-size: 10px; color: #999;">
          东部
         </div>
        </div>
        <img alt="公牛队标志" src="https://placehold.co/30x30/ce1141/ffffff?text=公牛" style="width: 30px; height: 30px; margin-left: 10px;"/>
       </div>
      </div>
     </div>
     <div style="text-align: center; font-size: 12px; color: #0078d4; padding: 10px; border-top: 1px solid #eee; margin-top: 10px;">
      查看更多 美国职业篮球联赛
     </div>
    </div>
    <!-- Calendar Card -->
    <div class="card card-small calendar-card">
     <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
      <span style="font-weight: bold;">
       2025
      </span>
      <i class="fas fa-ellipsis-h">
      </i>
     </div>
     <div class="calendar-header">
      <div class="calendar-date">
       2月9日 星期日
      </div>
      <div style="color: #ff6700;">
       春节
      </div>
     </div>
     <div style="font-size: 12px; color: #999; margin-bottom: 10px;">
      农历正月初一
     </div>
     <div style="font-size: 12px; margin-bottom: 15px;">
      春节,传统上是中国最重要的节日,是中国人民辞旧迎新的重要庆祝活动。
     </div>
     <div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
      <div style="font-size: 12px; color: #999;">
       日
      </div>
      <div style="font-size: 12px; color: #999;">
       一
      </div>
      <div style="font-size: 12px; color: #999;">
       二
      </div>
      <div style="font-size: 12px; color: #999;">
       三
      </div>
      <div style="font-size: 12px; color: #999;">
       四
      </div>
      <div style="font-size: 12px; color: #999;">
       五
      </div>
      <div style="font-size: 12px; color: #999;">
       六
      </div>
     </div>
     <div class="calendar-grid">
      <div class="calendar-day">
       3
      </div>
      <div class="calendar-day">
       4
      </div>
      <div class="calendar-day">
       5
      </div>
      <div class="calendar-day">
       6
      </div>
      <div class="calendar-day">
       7
      </div>
      <div class="calendar-day">
       8
      </div>
      <div class="calendar-day today">
       9
      </div>
     </div>
     <div style="text-align: center; font-size: 12px; color: #0078d4; margin-top: 15px;">
      查看更多日历
     </div>
    </div>
   </div>
  </div>
 </body>
</html>

我们可以看到相比GPT-4o,Claude还是可以还原出页面的整体布局结构,虽然不完美,但也在在努力尝试恢复出各个卡片的样式。相比GPT-4o,有明显的改进,但还是需要人工在后期做非常多的修改工作。

从以上的几个案例可以看到

  • 基于多模态大模型的Design to code方案,可以实用简单的prompt来实现转换工作,相比基于规则、CV的方法,基于大模型的转换方案,使得程序员的开发工作变得异常简单。
  • 在简单的UI设计稿转换上,大模型都表现相当优秀,Claude的还原精度可以用经验来形容。
  • 对于复杂的UI,大模型的表现普遍不佳,但Claude的优势非常明显,比较接近可以实用的效果。对于复杂的UI,可以尝试先进行切分,将相对简单的UI组件输入给大模型,生成网页代码后,再由人工来进行合并。

参考文献

[1] Tony Beltramelli. pix2code: Generating code from a graphical user interface screenshot. In
Proceedings of the ACM SIGCHI Symposium on Engineering Interactive Computing Systems,
EICS 2018, Paris, France, June 19-22, 2018, pages 3:1–3:6. ACM, 2018. doi: 10.1145/3220134.
3220135.

[2] Hugo Laurenccon, L’eo Tronchon, and Victor Sanh. Unlocking the conversion of web screenshots
into html code with the websight dataset. 2024.

[3] screenshot to code project

0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
最旧
最新 最多投票
内联反馈
查看所有评论