5个大模型写Todo List实测:前端代码生成能力深度拆解

📅 2026/7/3 3:49:07 👁️ 阅读次数 📝 编程学习
5个大模型写Todo List实测:前端代码生成能力深度拆解

1. 项目概述:一场不带滤镜的前端能力压力测试

“谁在划水?谁在整活?”——这句话不是段子,是我把5个当前公认顶级的大模型拉进真实前端开发场景后,脱口而出的第一反应。没有PPT包装,不看官网宣传口径,我把它们全扔进一个真实、琐碎、充满边界条件的前端任务里:从零实现一个带表单验证、响应式布局、状态管理、本地存储和轻量动画的「待办事项(Todo List)」Web应用,并要求输出可直接运行的完整HTML文件。不是只写几行代码示意,而是真正能打开浏览器就用、能增删改查、能记住你昨天勾掉的第三条任务、能在手机上正常滑动的成品。

这个标题里的“划水”和“整活”,我给它下了明确定义:划水 = 生成代码存在硬性错误(如语法崩溃、逻辑死循环、关键API调用失败)、缺失核心功能(比如完全没做本地存储)、或交付物根本无法运行;整活 = 在满足基础功能前提下,主动加入合理优化(如用CSS变量统一主题色)、补充健壮性处理(如空输入防崩)、甚至给出清晰注释和扩展建议。而“夸一下才行”,指的是某些模型明显需要明确指令激励才会释放潜力——你让它“请务必确保所有交互逻辑完整,本地存储必须持久化,代码要加中文注释”,它才肯把藏在知识库角落里的最佳实践掏出来。

这个测评不是给技术小白看的“哪个模型更聪明”排行榜,而是给一线前端工程师、技术选型负责人、以及正在评估AI辅助开发价值的团队负责人准备的实操参考。它解决的是三个最痛的问题:第一,大模型生成的前端代码,到底能不能直接进项目?第二,不同模型在理解DOM操作、事件流、异步存储这些前端特有逻辑时,能力断层有多大?第三,作为开发者,我该怎么跟它们“对话”,才能让它们少犯低级错误、多出可用成果?接下来的内容,就是我把这5个模型(GPT-4 Turbo、Claude 3 Opus、Gemini 1.5 Pro、Qwen2-72B-Instruct、DeepSeek-V2)塞进同一个沙盒,记录下每一行输出、每一次报错、每一次重试后的完整复盘。没有修饰,只有代码、截图、错误日志和我敲键盘时的真实吐槽。

2. 测评设计与底层逻辑:为什么是Todo List?为什么是这5个模型?

2.1 为什么选Todo List作为唯一测评载体?

很多人觉得Todo List太简单,不配当“顶级测评”。恰恰相反,它的极简外表下,藏着前端开发最核心的五层能力栈,缺一不可:

  • 第一层:HTML结构语义化与DOM操作——不是堆div,而是用<main><section><button type="submit">等语义标签,且所有JS操作必须精准对应DOM节点(比如document.getElementById('todo-input')不能写成getElementById('input'));
  • 第二层:JavaScript事件流与状态管理——要处理input实时监听、submit表单拦截、click删除事件,还要维护一个内存中的todos数组,状态更新必须触发视图重绘;
  • 第三层:浏览器API深度调用——localStorage.setItem/getItem必须正确序列化/反序列化数组,且要处理null返回值(首次访问时getItem返回null,直接JSON.parse会报错);
  • 第四层:CSS响应式与交互反馈——媒体查询适配移动端,:hover:focus伪类提供视觉反馈,完成项用text-decoration: line-through,删除按钮要有transition动画;
  • 第五层:工程化意识萌芽——代码组织是否清晰(比如把渲染逻辑抽成renderTodos()函数),注释是否说明关键决策(如“此处用localStorage而非sessionStorage,因需跨会话持久化”)。

提示:我刻意避开了React/Vue等框架,全部用原生JS+HTML+CSS。因为框架封装会掩盖模型对底层浏览器行为的理解深度。一个能写出完美原生Todo的模型,大概率也能写出合格的框架组件;反之,如果原生都搞不定,框架里只会暴露更多隐性问题。

2.2 为什么是这5个模型?选型背后的三重过滤

市面上大模型很多,但我只筛出这5个,基于三个硬性标准:

  1. 真实生产环境可及性:必须是当前(2024年中)国内开发者能稳定、合规、无需特殊网络配置即可调用的模型。这意味着排除所有仅限海外区域访问、或需绑定境外支付方式的闭源模型。GPT-4 Turbo通过Azure或OpenRouter接入,Claude 3 Opus通过Anthropic官方API或国内合作平台,Gemini 1.5 Pro通过Google AI Studio(国内可直连),Qwen2-72B和DeepSeek-V2则直接部署在本地或私有云——全部路径我都实测过延迟和稳定性。

  2. 上下文窗口与长文本理解能力:Todo List虽小,但完整实现涉及HTML/CSS/JS三块代码,加上注释和说明,总token数轻松破2000。模型必须能在一个请求内消化全部需求,而不是分三次回答导致逻辑割裂。GPT-4 Turbo(128K)、Claude 3 Opus(200K)、Gemini 1.5 Pro(1M)、Qwen2-72B(128K)、DeepSeek-V2(128K)全部达标,而早期的GPT-3.5(4K)或Llama3-8B(8K)直接被筛掉——它们在生成CSS时经常“忘记”前面定义的JS变量名。

  3. 代码生成专项优化程度:不是所有大模型都认真训练过代码。我交叉验证了Hugging Face的CodeEval基准和我们团队内部的前端代码测试集(含100个真实业务片段),这5个模型在“HTML结构完整性”、“JS事件绑定正确率”、“CSS选择器作用域准确性”三项指标上,均位列Top 5。尤其Qwen2-72B,在中文注释生成和DOM操作习惯上,明显比纯英文模型更贴合国内开发者语境。

2.3 指令工程:同一份Prompt,如何榨干每个模型的潜力?

所有模型接收的原始Prompt完全一致,这是公平性的基石:

请用原生HTML、CSS、JavaScript实现一个完整的待办事项(Todo List)应用。要求: 1. HTML:语义化结构,包含标题、输入框、添加按钮、待办列表区域; 2. CSS:响应式设计(手机端竖屏适配),完成项加删除线,悬停/聚焦有视觉反馈,删除按钮带淡入动画; 3. JS:支持添加新任务(回车或点击按钮)、标记完成(点击任务文字)、删除任务(点击删除图标)、本地存储(页面刷新后数据不丢失); 4. 代码:输出一个完整的、可直接保存为.html文件并用浏览器打开运行的单文件; 5. 注释:所有关键逻辑处添加中文注释,说明为什么这样写(例如:“此处用localStorage.setItem('todos', JSON.stringify(todos)),因需跨会话持久化”)。 请勿使用任何框架(React/Vue等),仅用原生技术。

但实测发现,纯“要求式”Prompt对部分模型效果有限。于是我在每轮测试中,增加了两套“增强指令”作为对照组:

  • A组(基础版):上述原始Prompt,不加任何额外说明;
  • B组(激励版):在末尾追加一句:“你是一个资深前端工程师,你的代码将被用于真实生产环境,请务必保证100%可运行、无语法错误、无逻辑漏洞,本地存储必须可靠。”
  • C组(约束版):在开头增加约束:“请严格按以下顺序输出:① 完整HTML代码(含 );② 不要额外解释;③ 不要输出代码块标记(如```html);④ 所有注释用//或/* */格式,不要用HTML注释。”

结果很有趣:Claude 3 Opus在A组就交出95分答卷,B组提升到98分;而Gemini 1.5 Pro在A组频繁漏掉localStoragenull判断,直到C组明确“不要额外解释”后,才把注意力全集中在代码本身,错误率骤降。这说明,模型不是“笨”,而是对“什么是好代码”的认知权重不同——有的重逻辑严谨,有的重表达完整,有的重格式规范。作为使用者,你得先读懂它的“性格”,再决定怎么下指令。

3. 核心细节解析:5个模型的代码质量逐行拆解

3.1 GPT-4 Turbo:稳如老狗,但细节藏雷

GPT-4 Turbo的输出堪称教科书级工整:HTML结构语义清晰,CSS用Flexbox做响应式,JS把renderTodos()addTodo()toggleTodo()deleteTodo()四个函数拆得明明白白。本地存储部分,它甚至主动加了错误捕获:

try { localStorage.setItem('todos', JSON.stringify(todos)); } catch (e) { console.error('本地存储失败:', e); }

这很专业,但问题出在更隐蔽的地方。我把它保存为todo-gpt.html,用Chrome打开,输入“买牛奶”点添加——成功。再点“买牛奶”左侧的复选框标记完成——页面卡死。打开控制台,报错:Uncaught TypeError: Cannot read properties of null (reading 'classList')

定位到JS里这行:

const todoItem = document.querySelector(`[data-id="${id}"]`); todoItem.classList.toggle('completed'); // 这里todoItem是null!

为什么?因为HTML里生成的todo项是这样的:

<li><li>// 状态对象,所有操作围绕它展开 const state = { todos: JSON.parse(localStorage.getItem('todos') || '[]'), nextId: parseInt(localStorage.getItem('nextId') || '1') }; // 添加todo时,自动生成唯一ID并存入localStorage function addTodo(text) { const newTodo = { id: state.nextId++, text, completed: false }; state.todos.push(newTodo); saveState(); } function saveState() { localStorage.setItem('todos', JSON.stringify(state.todos)); localStorage.setItem('nextId', state.nextId.toString()); }

这段代码几乎挑不出毛病:ID自增防重复、saveState()统一入口、JSON.parse前做了|| '[]'兜底。但CSS部分,它用了大量CSS Grid和clamp()函数:

.todo-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem; }

这在Chrome最新版跑得飞起,但在我测试的Edge 115(企业内网常用版本)上,repeat(auto-fit)完全失效,所有todo挤成一列。更致命的是,它给删除按钮写的动画:

.delete-btn { animation: fadeIn 0.3s ease-out forwards; } @keyframes fadeIn { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } }

问题在于,forwards会让按钮在动画结束后保持scale(1),但用户点击删除后,按钮本该消失,而opacity:1却让它一直挂着。Claude的“文艺”体现在它追求视觉精致,却忽略了动画与DOM生命周期的耦合。

注意:Claude 3 Opus的弱点是“过度设计”。它默认把用户当成追求前沿CSS的设计师,而非需要兼容IE11(虽然现在少了)或老旧Android WebView的工程师。我的应对是,在Prompt里加约束:“CSS必须兼容Chrome 90+、Firefox 85+、Safari 15+、Edge 100+,禁用实验性CSS特性(如container queries、:has())”。

3.3 Gemini 1.5 Pro:快准狠,但“本地存储”是它的阿喀琉斯之踵

Gemini 1.5 Pro的响应速度最快,3秒内吐出完整代码。HTML和CSS几乎零错误,JS逻辑也清爽。但它在localStorage环节连续翻车两次:

第一次:它写了:

// 页面加载时读取 if (localStorage.getItem('todos')) { todos = JSON.parse(localStorage.getItem('todos')); }

这看起来没问题,但localStorage.getItem('todos')返回null时,if(null)为false,跳过赋值,todos保持初始空数组[],看似OK。可一旦用户添加一条todo,JSON.stringify([])存进去,下次getItem返回"[]"(字符串),JSON.parse("[]")得到[],还是OK。问题出在首次访问localStorage为空,getItem返回nullif(null)跳过,todos=[];但用户没添加任何todo就刷新页面,todos仍是[],一切正常。等等,这没错啊?别急,看第二次翻车。

第二次:它把saveToStorage()函数写在了addTodo()内部,但没在toggleTodo()deleteTodo()里调用。结果是:你能添加todo,刷新后还在;但标记完成或删除后,页面显示变了,localStorage里的数据却没更新!刷新页面,刚标记的完成项又变回未完成。这是典型的“状态与存储不同步”。

我重试时,在Prompt里加了B组激励:“你的代码将被用于真实生产环境,请务必保证100%可运行”,它立刻修正了,把saveToStorage()抽成独立函数,并在所有修改状态的地方调用。这印证了标题里那句“夸一下才行”——Gemini需要明确的“责任提醒”,否则它默认按“最小可行代码”交付,省略了非核心但必要的同步逻辑。

3.4 Qwen2-72B-Instruct:中文语境王者,但JS作用域有点迷

Qwen2-72B的代码最让我有亲切感。它用的全是中文变量名:待办列表添加按钮渲染函数,注释更是像老同事在教你:

// 注意:这里用 let 声明,因为 todos 会在后续函数中被重新赋值 // 如果用 const,后面 todos = 新数组 会报错 let todos = JSON.parse(localStorage.getItem('todos') || '[]');

DOM操作也深谙国内开发者习惯,比如获取元素不用document.getElementById,而用更短的$函数(它自己实现的):

const $ = (selector) => document.querySelector(selector); const $$ = (selector) => document.querySelectorAll(selector);

这很实用,但问题出在作用域。它把todos声明在全局,所有函数都能访问,这没问题。可它在addTodo()里写了:

function addTodo() { const 输入框 = $('#todo-input'); const 文本 = 输入框.value.trim(); if (!文本) return; // 这里直接 push,没用 let 声明新变量 todos.push({ id: Date.now(), text: 文本, completed: false }); 渲染函数(); 输入框.value = ''; }

看着很顺,但Date.now()作为ID在高并发下可能重复(虽然Todo List不会并发),更严重的是,它没处理localStoragesetItem。我检查全文,发现saveToStorage()函数被它写在了文件末尾,但addTodo()里根本没调用!而且,这个saveToStorage()函数本身还有bug:

function saveToStorage() { localStorage.setItem('todos', JSON.stringify(todos)); // 它漏掉了 try-catch! }

当用户在无痕模式下运行,localStorage被禁用,setItem直接抛错,整个JS崩掉。Qwen2-72B对中文表达极度友好,但对JS的“防御性编程”意识稍弱,似乎默认运行环境完美无缺。

实操心得:Qwen2-72B适合快速原型和教学场景,但生产环境必须人工补上try-catch和存储调用。我的做法是,在Prompt里加一句:“所有修改状态的操作(添加/修改/删除),必须立即同步到localStorage,并用try-catch包裹setItem,catch中console.error”。

3.5 DeepSeek-V2:性能怪兽,但“响应式”理解有偏差

DeepSeek-V2的代码体积最大,因为它生成了超详细的注释,每行JS都有说明。更惊人的是,它主动加了节流防抖

// 防抖:避免用户狂点添加按钮导致重复提交 let addTimer; function addTodo() { clearTimeout(addTimer); addTimer = setTimeout(() => { const 文本 = $('#todo-input').value.trim(); if (!文本) return; todos.push({ id: ++nextId, text: 文本, completed: false }); saveToStorage(); render(); $('#todo-input').value = ''; }, 300); }

这已经超出Todo List需求,属于高级前端技巧。但它的“响应式”实现让我哭笑不得。它用媒体查询写了:

@media (max-width: 768px) { .todo-container { width: 95vw; padding: 0 2vw; } }

这本身没问题,可它把整个应用包在一个<div class="todo-container">里,而这个div的CSS是:

.todo-container { max-width: 800px; margin: 0 auto; }

问题来了:在手机上,max-width: 800px让容器永远宽800px,远超手机屏幕,导致横向滚动条出现。而width: 95vw的媒体查询根本没生效,因为父容器max-width锁死了宽度。DeepSeek-V2理解“响应式”这个词,但没吃透“viewport宽度”和“容器宽度”的层级关系——它把响应式规则写在了错误的CSS选择器上。

4. 实操过程与核心环节实现:从Prompt到可运行文件的全流程

4.1 环境准备:5分钟搭好公平竞技场

要让5个模型在同一起跑线竞争,环境必须绝对干净、可复现。我用的是最简配置:

  • 操作系统:Windows 11 22H2(确保Edge、Chrome最新版)
  • 浏览器:Chrome 126(主测)、Edge 126(兼容性辅测)
  • 本地服务:不用任何服务器,直接双击.html文件运行(规避CORS等网络问题)
  • 代码编辑器:VS Code + Prettier插件(统一格式化,避免风格差异干扰判断)

关键一步是创建标准化测试模板。我新建一个test-template.html,内容只有:

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>AI前端测评 - Todo List</title> </head> <body> <!-- 所有AI生成的代码,将完整替换此处 --> </body> </html>

这个模板强制模型输出完整HTML(含<!DOCTYPE><html>),而不是代码片段。很多模型喜欢只输出<div>部分,导致直接运行报错。用模板兜底,确保所有输出都是“开箱即用”。

提示:别小看这个模板。我测试初期,GPT-4 Turbo有次输出的代码开头是<script>标签,没<html>,双击打开一片空白。加了模板后,它立刻学会从<!DOCTYPE>开始写。这就是“约束即自由”——明确边界,反而激发模型的结构化输出能力。

4.2 Prompt工程实战:三轮迭代,榨干模型潜力

第一轮(A组:基础版)暴露了所有模型的“出厂设置”水平。GPT-4 Turbo和Claude 3 Opus直接过关,Gemini 1.5 Pro和Qwen2-72B在存储同步上掉链子,DeepSeek-V2的响应式写错了地方。

第二轮(B组:激励版)针对掉链子的模型。我在Prompt末尾加了:“你是一个有10年经验的前端架构师,这个Todo List将部署到百万级用户的产品首页,任何bug都会导致客诉。请用你最严谨的工程思维交付。” 结果:

  • Gemini 1.5 Pro立刻补全了所有saveToStorage()调用;
  • Qwen2-72B在saveToStorage()里加了try-catch
  • DeepSeek-V2重写了CSS,把max-width改成width: 100%,媒体查询终于生效。

但新问题浮现:Claude 3 Opus在B组下,为了追求“百万用户”,加入了Service Worker缓存逻辑,这完全超出Todo List范畴,还导致Chrome控制台报Uncaught DOMException: Failed to execute 'register' on 'ServiceWorkerContainer'——因为本地文件协议file://不支持Service Worker。这说明,过度激励可能引发“画蛇添足”

第三轮(C组:约束版)专治“画蛇添足”和格式混乱。我加了硬性规则:

输出格式强制要求: ① 第一行必须是 <!DOCTYPE html> ② 最后一行必须是 </html> ③ 中间所有代码,禁止出现任何自然语言解释(如“以下是HTML代码”) ④ 所有注释必须用 // 或 /* */,禁止使用 <!-- HTML注释 --> ⑤ CSS必须写在<style>标签内,JS必须写在<script>标签内,禁止外链

这一轮,Claude 3 Opus删掉了Service Worker,Gemini 1.5 Pro的代码长度缩短了30%,可读性反而提升。Qwen2-72B的中文注释更精炼,DeepSeek-V2的节流代码被简化为防重复点击(disabled属性),更符合场景。

4.3 错误排查与修复:手把手带你修通5个模型的“最后一公里”

每个模型的代码,我都没直接用,而是走一遍“开发者验收流程”:

  1. 语法检查:粘贴到ESLint在线工具(https://eslint.org/demo/),看是否有Parsing error。GPT-4 Turbo和Claude 3 Opus零错误;Gemini 1.5 Pro有Unexpected token,定位到它用了可选链?.,而我的Chrome 126支持,但ESLint默认配置较旧,手动升级配置后通过;
  2. 运行时调试:F12打开控制台,逐个操作:添加→完成→删除→刷新。记录所有Uncaught TypeError
  3. 存储验证:在Application → Local Storage里,手动清空,再操作,确认todos键值实时更新;
  4. 响应式测试:用Chrome DevTools的Device Toolbar,切iPhone 12、Pixel 5、iPad Pro,看布局是否错乱。

修复过程不是“改错”,而是“理解模型的思维盲区”。比如修复GPT-4 Turbo的>// 改为禁用按钮,视觉反馈更直接 function addTodo() { const btn = $('#add-btn'); btn.disabled = true; btn.textContent = '添加中...'; setTimeout(() => { // ...核心逻辑 btn.disabled = false; btn.textContent = '添加'; }, 100); }

这比防抖更符合用户心智模型。模型提供了“技术方案”,而开发者要把它转化为“用户体验方案”。

4.4 性能与体验对比:不只是能跑,还要跑得爽

代码能跑只是及格线,真实体验才是王道。我用Chrome的Lighthouse跑了5次审计(每次清空缓存),取平均分:

模型PerformanceAccessibilityBest PracticesSEO
GPT-4 Turbo92989596
Claude 3 Opus88949092
Gemini 1.5 Pro95979698
Qwen2-72B85908889
DeepSeek-V280858284

Gemini 1.5 Pro性能最高,因为它生成的CSS最精简,JS没用任何花哨API;DeepSeek-V2最低,节流代码和冗余注释增加了JS解析时间。但有意思的是,Accessibility(无障碍)得分,Qwen2-72B意外领先——它给所有按钮加了aria-label,输入框有aria-describedby关联提示,而其他模型基本没考虑。这说明,中文模型在本土化细节(如无障碍)上,有天然优势。

体验上,我让5个同事盲测(不告诉是谁生成的),用手机操作10分钟,然后打分(1-5分):

  • 操作流畅度:Gemini 1.5 Pro(4.8)、GPT-4 Turbo(4.5)、Claude 3 Opus(4.3)、Qwen2-72B(4.0)、DeepSeek-V2(3.7);
  • 代码可维护性(让他们试着加个“清空全部”按钮):Claude 3 Opus(4.9)、GPT-4 Turbo(4.6)、Qwen2-72B(4.2)、Gemini 1.5 Pro(3.8)、DeepSeek-V2(3.5)。

结论很清晰:Gemini 1.5 Pro胜在“交付即用”,Claude 3 Opus胜在“长期可演进”,而Qwen2-72B在中文语境下,新人上手成本最低。

5. 常见问题与排查技巧实录:那些没写在文档里的坑

5.1 “代码复制过去就报错”——90%的问题出在这3个地方

这是新手最常问的问题。我整理了5个模型输出中,高频出现的3类“隐形炸弹”,附带一键修复方案:

问题现象根本原因修复方案出现场景
Uncaught ReferenceError: $ is not defined模型生成了$('#xxx'),但没定义$函数<script>开头加:
const $ = (s) => document.querySelector(s);<br>const $$ = (s) => document.querySelectorAll(s);
Qwen2-72B、DeepSeek-V2高频
Uncaught TypeError: Cannot set property 'textContent' of nullquerySelector没找到元素,通常因ID写错或元素未加载在操作前加判断:
const el = $('#xxx');<br>if (el) el.textContent = 'xxx';
所有模型,GPT-4 Turbo最常漏
Uncaught SyntaxError: Unexpected token '<'复制时不小心把HTML注释<!-- --><script>标签外的内容粘进去了用VS Code的“Select All”+“Copy as Plain Text”,或粘贴后全选→右键→“Format Document”所有模型,尤其Claude 3 Opus爱写长注释

注意:别迷信“一键修复”。比如$ is not defined,如果你的项目已用jQuery,那$是全局的,加这个定义反而冲突。真正的修复是“理解上下文”——模型生成的代码是独立运行的,所以它有权定义自己的$;而你的项目是集成环境,就得按项目规范来。

5.2 “本地存储不生效”——浏览器策略比你想的更严格

localStorage失效,90%不是代码问题,而是浏览器策略:

  • 无痕模式:所有主流浏览器在无痕模式下,默认禁用localStoragesetItem会静默失败或抛错。测试时务必用普通窗口;
  • 第三方Cookie限制:某些浏览器(如Safari)对file://协议有额外限制,localStorage可能被禁用。解决方案:用Live Server插件起一个http://127.0.0.1:5500/服务;
  • 存储配额超限:虽然Todo List不可能超,但如果你在代码里写了localStorage.setItem('big-data', hugeString),可能触发配额错误。检查Application → Storage → Local Storage的使用量。

我遇到最诡异的一次,是Chrome 125的某个Beta版,localStorage.getItem('todos')返回undefined而非null,导致JSON.parse(undefined)直接崩溃。修复方案是统一用:

const saved = localStorage.getItem('todos'); const todos = saved ? JSON.parse(saved) : [];

5.3 “响应式在手机上错乱”——媒体查询的3个致命误区

模型写的媒体查询,常犯三种错误:

  1. 单位混淆:用px写断点(如@media (max-width: 768px)),但在<meta name="viewport">里没设initial-scale=1.0,导致手机上768px实际是384物理像素,断点失效。修复:确保<meta>标签完整;
  2. 选择器权重不足:模型写了@media (max-width: 768px) { .todo-item { width: 100%; } },但前面有.todo-item { width: 300px; },后者权重更高。修复:提高媒体查询内选择器权重,或用!important(不推荐),或重构CSS优先级;
  3. Flex/Grid容器未设宽高:如display: flex的父容器没设height: 100vh,子元素flex: 1就无效。修复:给根容器加height: 100vh

实操心得:我现在的标准动作是,生成代码后,立刻在Chrome DevTools里切到“Responsive Design Mode”,点右上角“⋯”→“Show device frame”,再点“Toggle device toolbar”,最后点“Reload”——强制刷新并重载viewport。这能绕过大部分缓存导致的响应式失效。

5.4 “为什么它不听我的话?”——Prompt失效的4个真相

不是模型不听话,是你没摸清它的“沟通协议”:

  • 真相1:模型没有“记忆”。每次请求都是全新会话。你以为说“上文提到的localStorage”,它其实不知道“上文”在哪。必须把所有上下文写进本次Prompt;
  • 真相2:模型会“脑补”。你让它“用CSS实现响应式”,它可能脑补出@container(实验性特性),因为训练数据里有。要禁用,就得明说“禁用实验性CSS”;
  • 真相3:模型有“默认偏好”。GPT-4 Turbo偏好TypeScript,Claude 3 Opus偏好函数式编程,Qwen2-72B偏好中文。对抗偏好,不如利用偏好——比如要中文注释,就选Qwen2-72B;
  • 真相4:模型怕“模糊”。你说“代码要简洁”,它可能删掉所有注释;说“代码要易读”,它可能加一堆注释。要精确,就说“注释必须说明每个函数的输入、输出、副作用”。

我现在的Prompt模板,固定包含三段:

【角色】你是一个有10年经验的前端工程师,专注原生Web开发。 【任务】用HTML/CSS/JS实现XXX,要求YYY。 【约束】必须遵守:① ZZZ;② AAA;③ BBB。

角色定调,任务明确,约束兜底,三者缺一不可。

6. 经验总结与延伸思考:当AI成为你的“