
写前端三件套HTMLCSSJS的文章很多但大多数要么太理论读完还是写不出页面要么太零散今天学个标签明天学个选择器学完就忘。这篇文章想换一种讲法不做大而全的百科式罗列而是用 3 小时带你走完一条“能动手、能验证、能看懂自己代码”的最小路径。先说判断零基础学前端最忌讳的不是笨而是顺序错了。很多人一上来就啃厚厚的参考书或者直接扎进 Vue、React 框架里结果 HTML 语义还没搞清就被组件、状态管理砸晕最后心态崩了。正确顺序应该是什么先用 HTML 搭骨架再用 CSS 做样式最后用 JS 加交互——这也是为什么业界把这三种语言叫做“前端三件套”。如果你正处在这些阶段这篇文章非常适合你完全零基础想转行或自学前端但不知道从哪里下手学过一点 HTML 和 CSS但 JS 一直没入门写不出交互效果想快速了解网页从“静态”到“动态”的完整过程再决定要不要深入。读完这篇文章你会亲手做出一个可交互的待办事项页面并理解背后每一行代码的作用。这个项目很小但它把 HTML 结构、CSS 布局、JS 事件处理、DOM 操作全部串起来了。跑通它你就等于掌握了一套“前端思考方式”。下面是 3 小时的学习路线时间段学习内容产出第 1 小时HTML 核心标签与页面结构一个语义清晰的页面骨架第 2 小时CSS 选择器、盒模型、Flex 布局一个整洁、具备现代感的页面第 3 小时JS 变量、事件、DOM 操作一个能增删数据的待办清单1. 这篇文章真正要解决的问题很多人问“前端难不难”这个问题很难一句话回答。更准确的问法是“你希望用前端解决什么问题”如果你只是想看懂网页、改改页面样式、给自己做个简单工具页那么前端三件套的入门成本非常低。低到什么程度呢你只需要一个浏览器再加一个文本编辑器比如 VS Code不需要安装复杂的开发环境不需要配置服务器写完 HTML 文件直接用浏览器打开就能看到效果。这种“所见即所得”的反馈速度是很多人愿意学前端的重要原因。但如果你是想马上找一份前端开发的工作那就需要清醒一点3 小时只能帮你建立完整的概念框架和动手能力基础距离企业用人要求还有不小的距离。本文的目标是把地基打牢而不是给你造一栋精装房。前端这个领域表面上是三个技术底层其实是两种思维结构思维用 HTML 把内容组织成树状结构让浏览器和搜索引擎都能理解变化思维用 CSS 控制视觉表现用 JS 响应用户行为让页面从“死”的变成“活”的。很多初学者写页面乱本质是结构思维没建立起来写交互总报错本质是变化思维没建立起来。这两种思维恰恰是这三小时里最值得你花精力体会的东西。具体到本文你会看到HTML 不是“背标签”而是“设计内容层级”CSS 不是“背属性”而是“理解布局规则”JS 不是“背语法”而是“理解数据和事件”。为了避免你学完就忘整个项目的核心主线是**“做一个待办事项页面”**。你没有看错就是很多人瞧不上眼的 Todo List。因为这个项目天然包含了前端最核心的几件事用户输入、列表渲染、数据增删、界面状态变化。能把这个项目做明白你已经超过了一半的“只看不练型选手”。2. HTML网页的结构骨架与核心标签2.1 HTML 是什么不是什么HTML 全称是 HyperText Markup Language超文本标记语言。注意它叫“标记语言”不是“编程语言”。它没有变量、没有逻辑判断、没有循环它的工作只有一件事用标签描述内容的结构。标签的书写形式非常简单由尖括号包裹的标签名组成通常有开始标签和结束标签。p这是一段文本/p也有少数自闭合标签比如换行标签br你要把 HTML 理解成一份“文档大纲”它告诉浏览器这里有标题这里是段落这里是一个链接那里是一张图片。至于标题用什么颜色、段落显示多大字号、图片显示多宽这些都不归 HTML 管而是 CSS 的工作。很多初学者刚学 HTML特别喜欢背标签什么article、section、aside、footer背得头大。这里给个建议先记住使用频率最高的 20 个标签其余的等用到再查。前端是一个极其依赖查文档的领域这不是丢人的事反而是从业常态。2.2 一份 HTML 文档的标准结构任何 HTML 文件打开后都是下面这个模板。它不需要你记VS Code 里输入!再按 Tab 键就能自动生成。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的第一个页面/title /head body h1你好前端/h1 p这是我的第一个页面。/p /body /html几个关键点解释一下!DOCTYPE html告诉浏览器当前文档使用的是 HTML5 标准。不要省略否则浏览器会进入“怪异模式”导致样式解析异常。html langzh-CN声明页面语言为中文这对无障碍访问和 SEO 都有影响。head存放页面的元信息比如字符集、视口配置、标题、外部样式表和脚本的引入。这里的 content 不会直接显示在页面上。meta charsetUTF-8指定字符编码为 UTF-8。如果不写页面上中文很可能变成乱码。meta nameviewport ...移动端适配必备控制页面在手机上的显示宽度。不写的话手机浏览器会把桌面端页面整体缩小显示体验很差。body所有用户能看到的页面内容都必须放进这里。记住一个习惯先写结构再填内容。不要一上来就急着打字先在脑子里想清楚这个页面由哪些模块组成每个模块是什么关系。2.3 常用的 HTML 标签与语义化下面这张表覆盖了日常开发中最常用的一批标签建议你先按这个范围学不要贪多。标签作用典型使用场景h1~h6标题一级到六级页面主标题、章节标题p段落正文文本a超链接跳转其他页面或锚点img图片展示图片素材ul/ol/li无序列表 / 有序列表 / 列表项导航菜单、商品列表div无语义的分块容器页面布局分区span无语义的行内容器对一段文本的部分内容做样式input输入框表单、搜索框button按钮提交、触发交互form表单容器收集用户输入nav导航区域顶部菜单栏header页头页面顶部区域main页面主要内容区主体内容容器footer页脚版权信息、底部链接那么“语义化”是什么意思现在很多表格布局时代的老前端喜欢全用div一把梭但语义化标签的初衷是让“代码自己说明自己”。你可以想象自己是一名阅读你代码的同事如果他打开文件第一眼就看到header、nav、main、footer会比看到一堆div classtop、div classmid、div idbottom轻松得多。更重要的是搜索引擎爬虫和屏幕阅读器都会根据语义标签来理解页面结构这对 SEO 和无障碍体验都有实实在在的好处。2.4 实战搭建待办页面的 HTML 骨架现在开始动手。创建一个新文件夹命名为todo-app在里面新建一个文件index.html写入下面的代码!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的待办清单/title link relstylesheet hrefstyle.css /head body div classapp h1 我的待办清单/h1 div classinput-area input typetext idtodoInput placeholder输入新的待办事项... button idaddBtn添加/button /div ul idtodoList li classtodo-item input typecheckbox classtodo-checkbox span学习 HTML 标签/span button classdelete-btn删除/button /li li classtodo-item input typecheckbox classtodo-checkbox span学习 CSS 布局/span button classdelete-btn删除/button /li /ul /div script srcscript.js/script /body /html注意几个细节link relstylesheet hrefstyle.css放在head中表示引入外部 CSS 文件script srcscript.js放在body的末尾。因为 JS 要操作 DOM而 DOM 必须等页面加载完才能操作。放在末尾可以避免“还没渲染完就开始找节点”的问题。我用了两个input一个是文本框一个是复选框它们都是普通的输入控件不要混淆。现在就差 CSS 和 JS 文件了。别急着关编辑器我们继续。3. CSS从“白底黑字”到“现代界面”3.1 CSS 到底是干什么的CSS 全称是 Cascading Style Sheets层叠样式表。它的核心价值在于把“内容”和“表现”分离。同样一份 HTML引用不同的 CSS可以呈现出完全不同的视觉风格。这就像同一件白 T 恤搭休闲裤是日常风搭半身裙是通勤风搭牛仔裤是街头风——衣服是 HTML搭配方案是 CSS。初学者最容易在 CSS 里遇到的困惑是为什么我设的颜色不生效为什么这个元素不居中要解决这些问题不能只背属性必须理解 CSS 的两个底层机制选择器决定“样式作用于哪个元素”盒模型决定“元素在页面中占多大空间、怎么排列”。3.2 选择器精准定位要修饰的元素CSS 选择器种类很多但入门阶段掌握下面五类就够用。选择器写法示例作用标签选择器标签名p { color: red; }选择所有p标签类选择器.类名.app { width: 500px; }选择所有classapp的元素ID 选择器#id名#addBtn { padding: 8px; }选择idaddBtn的元素后代选择器父 子.input-area input { }选择父元素内部的所有匹配子元素伪类选择器元素:hoverbutton:hover { }元素处于某个状态时应用样式这里特别提醒两个高频误区第一ID 在同一个页面里只能出现一次。它是元素的“身份证号”不能重复使用。如果需要为多个元素设置相同样式应该使用类选择器。第二后代选择器并不要求必须是父子关系只要是祖先和后代即可。比如.app input会选择.app内部所有层级的input即使中间还包裹了div。关于伪类选择器很多初学者被“伪”字吓到其实它不过是指“元素在某一种特殊状态下的样式”。最常见的:hover是鼠标悬停。此外你还会经常见到:first-child、:last-child、:nth-child()这类用于选位置的伪类它们在做列表样式时非常有用。3.3 盒模型理解空间的底层逻辑在 CSS 中每一个元素都可以看作一个盒子。从内到外分别是Content内容区文本或图片显示的区域Padding内边距内容与边框之间的距离Border边框盒子的边框Margin外边距盒子与其他元素之间的间距。一个盒子的实际宽度公式是面试题也爱考的经典问题实际宽度 width padding-left padding-right border-left border-right这意味着如果你给一个元素设置了width: 200px和padding: 20px它最终的视觉宽度不是 200px而是 240px。这个问题困扰过无数新手因为它直接导致“明明设置了宽度却还是溢出”的现象。解决办法有两个一是记住公式计算时手动扣除。二是使用box-sizing属性把宽度计算方式从content-box改成border-box* { box-sizing: border-box; }个人强烈建议你在所有新项目里都加上这一行。border-box的意思是你设置的width就是元素最终占据的宽度padding 和 border 都在这 200px 内部消化。这样一来心智负担会小很多。3.4 布局方式别急着学 Grid先把 Flex 用熟CSS 发展到今天主流的布局方式已经不再是float更不是position一点点拼凑。你要学的下一个重点就是Flexbox弹性布局。Flex 最核心的一句话是让容器里的子元素按照主轴方向排列并自动处理空间分配与对齐。使用方式很简单给父容器写上display: flex它的直接子元素就会变成“弹性项”沿水平方向排成一行。.input-area { display: flex; gap: 8px; }这是 Flex 布局中最高频、最容易见效的写法之一。gap用于控制子元素之间的间距。再用justify-content控制水平方向的对齐比如center居中、space-between两端对齐用align-items控制垂直方向的对齐比如center居中对齐。初学者常犯的错是把 Flex 属性写在子元素上。记住display: flex、justify-content、align-items都是写在父容器上的。子元素只需要通过flex: 1这类属性告诉浏览器“我要占据剩余空间”。3.5 完整 CSS让待办页面“活”起来现在在todo-app文件夹下新建一个style.css写入下面的代码/* 文件路径todo-app/style.css */ * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: -apple-system, Segoe UI, PingFang SC, Microsoft YaHei, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; } .app { width: 480px; max-width: 90%; background: #ffffff; border-radius: 16px; padding: 24px; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2); } .app h1 { text-align: center; font-size: 24px; color: #333; margin-bottom: 16px; } .input-area { display: flex; gap: 8px; margin-bottom: 16px; } #todoInput { flex: 1; padding: 10px 14px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; outline: none; transition: border-color 0.2s; } #todoInput:focus { border-color: #667eea; } #addBtn { padding: 10px 18px; background-color: #667eea; color: #fff; border: none; border-radius: 8px; font-size: 14px; cursor: pointer; transition: background-color 0.2s; } #addBtn:hover { background-color: #5a6fd6; } #todoList { list-style: none; } .todo-item { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-bottom: 1px solid #f0f0f0; } .todo-item:last-child { border-bottom: none; } .todo-item span { flex: 1; font-size: 15px; color: #444; } .todo-item input[typecheckbox] { width: 18px; height: 18px; cursor: pointer; } .delete-btn { padding: 4px 10px; background-color: #ff6b6b; color: #fff; border: none; border-radius: 6px; font-size: 12px; cursor: pointer; } .delete-btn:hover { background-color: #e05555; } .todo-item.completed span { text-decoration: line-through; color: #aaa; }这段 CSS 并不是随便写的每个块都在解决一个具体问题body上的display: flexalign-items: centerjustify-content: center实现整屏水平垂直居中。这个技巧是“页面居中”话题的标配答案.input-area上的display: flex让输入框和按钮排在同一行输入框用flex: 1自动填满剩余宽度.todo-item用display: flex排列复选框、文本和删除按钮.todo-item.completed span用text-decoration: line-through实现删除线效果这是后面 JS 联动的基础。此时你在浏览器里打开index.html页面已经不再是白底黑字而是一个带渐变色背景、居中卡片、态度鲜明的现代化小应用了。4. JavaScript让页面拥有“生命”4.1 为什么需要 JSHTML 负责内容CSS 负责样式但它们都改变不了页面的行为。你不能在纯 HTML 里实现“点击按钮新增一行”也不能在纯 CSS 里实现“输入内容后按下回车自动提交”。而 JS 的存在就是为网页提供动态行为。所谓“动态”其实就两件事响应用户操作、更新页面内容。不过JS 和传统编程语言不太一样的地方在于它从诞生起就绑定在浏览器环境里。在浏览器里JS 通过document对象来操作 DOMDocument Object Model文档对象模型。理解 DOM 是理解前端交互的关键。浏览器在加载 HTML 后会把标签解析成一棵倒挂的树我们称它为“DOM 树”。每一个标签都变成了这棵树上的一只“节点对象”。JS 能通过操作这些节点来改变网页上用户看到的任何一个元素——改文字、加样式、增节点、删节点。简单说HTML 是静态的买房合同DOM 是那套能随时重新装修的房子JS 就是你的装修队。没有 JS房子再好也就那样有了 JS你才能按需改造。4.2 变量、数据类型与常用语法JavaScript 的语法面非常广但一个“能写交互”的入门者真正需要掌握的语法其实很少。变量声明可以使用let和const。const用于不会被重新赋值的变量let用于会被重新赋值的变量。var是老写法现在推荐尽量避免。const appTitle 我的待办清单; let count 0;数据类型入门阶段你最需要关注的是字符串string、数字number、布尔值boolean、对象object、数组array。函数把一段逻辑封装起来。function addTodo() { // 具体逻辑 }事件监听JS 最核心的交互方式。const btn document.getElementById(addBtn); btn.addEventListener(click, addTodo);模板字符串字符串拼接的现代化写法。const text 当前有 ${count} 条待办;4.3 获取 DOM 元素与操作属性JS 操作 DOM第一步永远是“找到要操作的元素”。最常用的三种 API 是API返回值使用场景document.getElementById(id)单个元素操作唯一元素document.querySelector(选择器)第一个匹配元素任意选择器document.querySelectorAll(选择器)NodeList类似数组操作一组元素找到元素后你能做什么最常用的有三个维度改文本element.textContent 新内容改样式element.style.color red改类名element.classList.add(completed)4.4 常用的 DOM 操作创建、追加、删除动态列表的基础操作就是这三板斧// 创建元素 const li document.createElement(li); // 给元素添加类名和内容 li.classList.add(todo-item); li.innerHTML input typecheckbox classtodo-checkboxspan${text}/spanbutton classdelete-btn删除/button; // 追加到父元素中 document.getElementById(todoList).appendChild(li);这里有一个经验之谈尽量使用textContent去设置用户输入的内容不要直接拼 HTML。因为如果用户输入的是img srcx onerroralert(1)这类字符串直接拼到 HTML 里就触发 XSS 攻击。虽然我们这是个学习项目但从第一天开始养成安全的习惯很重要。4.5 完整的 JS 逻辑实现现在在todo-app文件夹下新建script.js写入下面的完整逻辑// 文件路径todo-app/script.js const todoInput document.getElementById(todoInput); const addBtn document.getElementById(addBtn); const todoList document.getElementById(todoList); // 新增待办事项 function addTodo() { const text todoInput.value.trim(); if (text ) { alert(请输入待办内容); return; } const li document.createElement(li); li.classList.add(todo-item); const checkbox document.createElement(input); checkbox.type checkbox; checkbox.classList.add(todo-checkbox); const span document.createElement(span); span.textContent text; const deleteBtn document.createElement(button); deleteBtn.textContent 删除; deleteBtn.classList.add(delete-btn); li.appendChild(checkbox); li.appendChild(span); li.appendChild(deleteBtn); // 复选切换完成状态 checkbox.addEventListener(change, function () { li.classList.toggle(completed); }); // 删除从列表中移除 deleteBtn.addEventListener(click, function () { todoList.removeChild(li); }); todoList.appendChild(li); todoInput.value ; todoInput.focus(); } // 回车提交绑定 input 上的 keydown 事件 todoInput.addEventListener(keydown, function (event) { if (event.key Enter) { addTodo(); } }); addBtn.addEventListener(click, addTodo);这段代码里有几个细节需要你品一下第一trim()的作用。用户输入可能带前后空格如果不处理会出现“看起来没内容但确实添加了”的 bug。trim()会去掉字符串首尾的空白符。如果去掉后是空字符串直接提示并返回不创建任何节点。第二为什么用createElement而不是innerHTML。前面提到过安全问题。更重要的createElement生成的是 DOM 对象我们需要给它的子元素单独绑定事件。如果用整段字符串插入后续绑定删除事件会比较绕。第三事件的绑定位置。注意删除按钮和复选框的事件是在li被创建之后就立即绑定的。这也是很多教程里容易忽略的细节如果你在 HTML 里写死了一个删除按钮你只需要在全局绑定一次但这里是动态创建的节点所以每个新节点都需要自己的事件监听器。第四toggle方法。如果类名completed存在则移除不存在则添加。这样复选框反复勾选时删除线效果能正常切换而不会被叠加出来。5. 完整示例与代码实现把三件套串起来现在三个文件已经全部就绪。整个项目的目录结构如下todo-app/ ├── index.html ├── style.css └── script.js各文件作用的对应关系可以用一张图表达index.html定义页面结构和初始内容style.css负责视觉表现包括居中、卡片、按钮样式、删除线等script.js负责交互逻辑包括输入、添加、勾选完成、删除。这三个文件互相配合构成了一个最简单也最完整的前端项目。这个“HTML 结构 CSS 样式 JS 交互”的协作模式会一直沿用到你接触任何复杂前端项目。5.1 如何运行与验证在浏览器中运行有两种方式方式一直接双击打开 index.html。这是最快的验证方式。双击后浏览器直接渲染页面不需要任何服务器。适合学习阶段使用。方式二使用 VS Code 的 Live Server 插件。如果你用 VS Code建议安装 Live Server 插件。安装后在index.html上右键选择 “Open with Live Server”浏览器会自动打开http://127.0.0.1:5500并实时刷新。这个方式更接近真实开发体验也方便调试。建议直接用方式二因为它能让你体会到“改代码、保存、浏览器立即更新”的开发节奏。5.2 预期效果完成之后你应该能看到一个居中显示的白色卡片卡片上方是标题“我的待办清单”输入框 按钮在同一行输入框有圆角边框按钮是蓝紫色列表里默认有两条待办在输入框里输入文字点击“添加”或按下回车新条目会以列表形式插入到最后勾选复选框后对应文字出现删除线并变为灰色点击“删除”按钮对应条目被移除。如果你看到以上所有效果说明你的 HTML、CSS、JS 已经形成了一个完整的闭环。5.3 如果失败怎么排查最可能出问题的地方是文件路径。请仔细检查index.html中link relstylesheet hrefstyle.css的路径是否与style.css在同一个目录下script srcscript.js的路径是否正确文件名的大小写是否一致比如style.css不要写成Style.css。如果点击“添加”没反应优先打开浏览器开发者工具F12切到 Console 标签页查看是否有红色报错。最常见的报错是Cannot read properties of null这种提示十有八九是getElementById的 id 名写错了或者脚本执行时该元素还不存在于 DOM 中。6. 常见问题与排查思路问题现象可能原因排查方式解决方案页面打开后中文显示乱码HTML 文件缺少meta charsetUTF-8查看head中是否声明字符编码在head中添加meta charsetUTF-8CSS 样式完全没有生效link标签的路径错误或文件名不匹配检查link标签的href与目录结构修正路径并统一文件名大小写输入框为空时点击添加也能添加没有做空值校验审查addTodo函数的trim()判断使用text.trim()判断为空时alert并return点击删除无效动态生成的元素没有绑定删除事件查看控制台报错和事件绑定代码每个动态节点的删除按钮都要单独绑定事件或用事件委托页面在手机上显示过宽缺少 viewport 配置检查head中 meta 标签添加meta nameviewport contentwidthdevice-width, initial-scale1.0勾选复选框后删除线不出现completed类名与 CSS 不匹配检查 JS 中classList.toggle和 CSS 中.completed span选择器统一类名拼写确保 CSS 写在style.css中找不到元素报错JS 执行时机早于 DOM 渲染打开 F12 查看 Console 报错位置把script放在body底部或使用DOMContentLoaded事件7. 最佳实践与工程建议项目虽然小但一些“工程习惯”可以尽早建立起来。很多人觉得这些习惯是“以后进公司再说”的事但实际上它们决定了一个人的代码能走多远。7.1 命名规范HTML id 和 class 使用小驼峰或短横线命名。推荐短横线风格如todo-input、todo-list。关键词之间用-分隔可读性好。JS 变量和函数使用小驼峰命名。如todoInput、addTodo。常量大写如MAX_COUNT。CSS 类名做到“见名知义”。.todo-item一眼就知道是待办事项条目.red-bg这种描述样式而不是描述语义的类名尽量少用。7.2 把逻辑拆成独立函数建议把“添加事件”和“添加逻辑”拆开而不是把所有代码都塞进一个click回调里。例如把addTodo定义成独立函数而addBtn.addEventListener(click, addTodo)只负责事件绑定。这样后续如果要加表单校验、数据持久化不会把同一个函数改得越来越长。7.3 防止脚本加载顺序的坑最简单也最稳妥的做法是把script标签放在body的末尾。因为浏览器解析 HTML 是按顺序从上往下执行的脚本放在底部时可以确保它执行时所有 DOM 元素都已经解析完成。如果你非要放在head里也不是不行但必须把操作 DOM 的代码包在DOMContentLoaded事件里document.addEventListener(DOMContentLoaded, function () { // 在这里执行 DOM 操作 });7.4 建议尽早尝试的扩展只用script.js里的逻辑还不够学到一个阶段后可以尝试把待办事项存入localStorage刷新页面后数据不丢失。这会顺便让你理解 JSON 的stringify和parse支持“双击编辑”把静态文本变成可编辑的输入框增加筛选功能全部分类、已完成、未完成三个 Tab增加统计功能在页面底部显示“剩余 X 项未完成”。这些扩展并不难但每一个都会逼着你回头复习三件套尤其是 DOM 和事件。7.5 关于学习路径的提醒到这里3 小时的内容基本就学完了。但想提醒一句本文的学习重点是“建立整体认知”不是“背语法大全”。学完后你应该具备的能力是看到一个设计稿能大致画出它由哪些 HTML 块组成看懂网上 Demo 里的 CSS 在做什么并能微调样式能独立给页面添加一个简单的交互功能遇到问题知道先看控制台、再查 MDN 文档。这些能力一旦建立后续无论学 Vue 还是 React都会顺畅很多。因为它们本质上是在帮你更高效地操作 DOM、管理数据和维护状态而底层依然是 HTML、CSS 和 JavaScript 这三件套。8. 总结与下一步这篇文章用了约 3 小时的阅读和动手时间带你完成了从零到一的第一个完整前端小项目。此时你手里应该已经有了三个文件index.html、style.css、script.js以及一个能输入、能添加、能勾选、能删除的待办页面。接下来你需要做一件事不要急着进入新知识先把这个项目反复“折腾”几遍。改改颜色调整一下布局给列表增加一个“全部清空”按钮把输入框的 placeholder 换成自己的语言。折腾的过程中你一定会踩到新的坑而踩坑、查错、修复才是真正的学习过程。如果再往后走推荐按这个顺序继续把待办数据存入localStorage理解前端持久化学习更系统的 CSS 知识重点掌握 Grid 布局、伪元素、过渡动画学习 ES6 常用语法解构、模板字符串、箭头函数、模块化接触 Vue 或 React用框架重构这个 Todo 项目。前端入门并没有想象中那么困难真正困难的是持续练习、在报错中积累经验并始终保持“把页面做出来”的动力。希望这个 3 小时的小项目能成为你前端路上第一个真正跑起来的起点。如果文章里有哪个环节还没看懂建议回到对应章节把代码再敲一遍——前端最怕“眼睛会了、手不会”一定要让手先动起来。