HTML + CSS + JavaScript 基础:网页的三件套
完成时间:约 45 分钟。读完后你能理解网页是怎么构成的,看懂 AI 生成的前端代码。
任何你在浏览器里看到的网页,都是由三样东西组成的:
| 角色 | 技术 | 类比 |
|---|---|---|
| 骨架 | HTML | 一栋房子的钢筋结构——决定有几个房间、门在哪、窗户在哪 |
| 装修 | CSS | 墙面颜色、地板材质、灯光——决定好不好看 |
| 电器 | JavaScript | 电灯开关、电梯、自动门——决定能不能互动 |
三者缺一不可。HTML 没有 CSS 就是毛坯房,没有 JavaScript 就是静态海报。
Part 1:HTML — 页面的骨架
Section titled “Part 1:HTML — 页面的骨架”HTML(HyperText Markup Language)用”标签”来描述页面内容。每个标签告诉浏览器”这是什么东西”。
标签的基本格式
Section titled “标签的基本格式”<标签名>内容</标签名>标签成对出现:开始标签 <h1> + 结束标签 </h1>。有些标签不需要关闭,比如 <img />、<input />。
最常用的 20 个标签
Section titled “最常用的 20 个标签”结构类
<div>...</div> <!-- 通用容器,最常用的"盒子" --><header>...</header> <!-- 页面头部(导航栏) --><main>...</main> <!-- 主要内容区 --><footer>...</footer> <!-- 页面底部 --><section>...</section> <!-- 一个内容区块 --><nav>...</nav> <!-- 导航区域 -->文本类
<h1>一级标题</h1> <!-- 最大的标题,页面通常只有一个 --><h2>二级标题</h2> <!-- 次级标题 --><h3>三级标题</h3> <!-- 更小的标题,最多到 h6 --><p>这是一段文字</p> <!-- 段落 --><span>行内文字</span> <!-- 一小段文字,不换行 --><a href="/about">关于</a> <!-- 链接,点击跳转 -->表单类(用户输入)
<input type="text" /> <!-- 文本输入框 --><input type="password" /> <!-- 密码输入框(内容显示为点) --><input type="email" /> <!-- 邮箱输入框 --><textarea>...</textarea> <!-- 多行文本框 --><select> <!-- 下拉选择 --> <option>选项1</option> <option>选项2</option></select><button>提交</button> <!-- 按钮 -->媒体类
<img src="photo.jpg" alt="照片描述" /> <!-- 图片 --><video src="demo.mp4"></video> <!-- 视频 -->列表类
<ul> <!-- 无序列表(圆点) --> <li>苹果</li> <li>香蕉</li></ul>
<ol> <!-- 有序列表(数字) --> <li>第一步</li> <li>第二步</li></ol>标签可以嵌套
Section titled “标签可以嵌套”标签像”套娃”一样嵌套,形成层级结构:
<div> <!-- 外层容器 --> <h2>用户列表</h2> <!-- 标题 --> <ul> <!-- 列表 --> <li>小明</li> <!-- 列表项 --> <li>小红</li> </ul></div>属性:给标签加额外信息
Section titled “属性:给标签加额外信息”标签可以有”属性”,写在开始标签里:
<a href="https://example.com" target="_blank">外部链接</a><!-- ^^^^ ^^^^^^^^^^^^^^ 链接地址 在新标签页打开 -->
<img src="avatar.jpg" alt="用户头像" width="100" /><!-- ^^^ ^^^ ^^^^^ 图片地址 描述文字 宽度 -->
<input type="text" placeholder="请输入用户名" required /><!-- ^^^^ ^^^^^^^^^^^ ^^^^^^^^ 输入类型 提示文字 必填 -->一个完整的 HTML 页面
Section titled “一个完整的 HTML 页面”<!DOCTYPE html> <!-- 声明这是 HTML5 --><html lang="zh"> <!-- 页面根元素,中文 --><head> <!-- 页面元信息(用户看不到) --> <meta charset="UTF-8"> <!-- 字符编码 --> <title>我的记账工具</title> <!-- 浏览器标签页标题 --></head><body> <!-- 页面正文(用户看到的) --> <header> <h1>记账工具</h1> <nav> <a href="/">首页</a> <a href="/about">关于</a> </nav> </header> <main> <h2>今日支出</h2> <p>总计:¥128.50</p> </main></body></html>你不需要从零写 HTML。 AI 会帮你生成。你需要的是看到
<div>、<button>、<input>时知道它们是什么。
Part 2:CSS — 页面的样式
Section titled “Part 2:CSS — 页面的样式”CSS(Cascading Style Sheets)控制 HTML 元素的外观:颜色、大小、位置、间距、动画等。
CSS 的基本格式
Section titled “CSS 的基本格式”选择器 { 属性: 值; 属性: 值;}示例:
h1 { color: red; /* 文字颜色:红色 */ font-size: 24px; /* 字体大小:24像素 */ margin-bottom: 16px; /* 下方间距:16像素 */}选择器:告诉 CSS “给谁加样式”
Section titled “选择器:告诉 CSS “给谁加样式””/* 标签选择器 — 所有 <p> 标签 */p { color: gray; }
/* class 选择器 — 所有 class="title" 的元素 */.title { font-size: 20px; }
/* id 选择器 — id="header" 的那一个元素 */#header { background: blue; }
/* 后代选择器 — .card 里面的所有 <p> */.card p { color: white; }在 HTML 里用 class 和 id 对应:
<h2 class="title">这是标题</h2><div id="header">这是头部</div>最常用的 CSS 属性
Section titled “最常用的 CSS 属性”文字相关
color: #333; /* 文字颜色 */font-size: 16px; /* 字体大小 */font-weight: bold; /* 粗体 */text-align: center; /* 文字居中 */line-height: 1.5; /* 行高 */盒模型:每个元素都是一个”盒子”
┌─────────── margin(外边距,元素和外部的间距)────────────┐│ ┌──────── border(边框)────────┐ ││ │ ┌───── padding(内边距,内容和边框的间距)──┐ ││ │ │ │ ││ │ │ content(内容) │ ││ │ │ │ ││ │ └─────────────────────────────────────────┘ ││ └──────────────────────────────────────────────────────┘│└─────────────────────────────────────────────────────────┘.card { padding: 16px; /* 内边距:内容到边框的距离 */ margin: 20px; /* 外边距:这个盒子和其他盒子的距离 */ border: 1px solid #ddd; /* 边框:1像素、实线、灰色 */ border-radius: 8px; /* 圆角 */}背景和尺寸
background-color: #f5f5f5; /* 背景颜色 */width: 100%; /* 宽度(占满父容器) */height: 200px; /* 高度 */max-width: 800px; /* 最大宽度 */显示和隐藏
display: none; /* 完全隐藏(不占位置) */display: block; /* 块级元素(独占一行) */display: flex; /* 弹性布局(最常用的排列方式) */visibility: hidden; /* 隐藏但仍占位置 */opacity: 0.5; /* 半透明 */Flexbox 布局(现代 CSS 最核心的布局方式)
Section titled “Flexbox 布局(现代 CSS 最核心的布局方式)”AI 生成的前端代码中 display: flex 无处不在。它的作用是让子元素灵活排列。
.container { display: flex; /* 开启 flex 布局 */ flex-direction: row; /* 横排(默认)。column = 竖排 */ justify-content: center; /* 主轴居中(横向居中) */ align-items: center; /* 交叉轴居中(纵向居中) */ gap: 16px; /* 子元素之间的间距 */}常见的 Flexbox 组合:
/* 水平居中 */display: flex; justify-content: center;
/* 垂直 + 水平居中(完美居中) */display: flex; justify-content: center; align-items: center;
/* 两端对齐(左右各一个) */display: flex; justify-content: space-between;
/* 竖着排列 */display: flex; flex-direction: column;响应式:不同屏幕用不同样式
Section titled “响应式:不同屏幕用不同样式”/* 默认样式(手机优先) */.sidebar { display: none; /* 手机上隐藏侧边栏 */}
/* 屏幕宽度 >= 768px 时(平板/电脑) */@media (min-width: 768px) { .sidebar { display: block; /* 大屏幕上显示侧边栏 */ }}Tailwind CSS — 本课程的样式方案
Section titled “Tailwind CSS — 本课程的样式方案”传统 CSS 写在单独文件里,Tailwind 把样式直接写在标签的 class 属性上。AI 生成的代码几乎都用 Tailwind。
<!-- 传统 CSS:写样式文件 + 给标签起 class 名 --><div class="card"> <h2 class="card-title">标题</h2></div>
<!-- Tailwind:样式就在标签上,不需要额外的 CSS 文件 --><div class="bg-white p-6 rounded-lg shadow-md"> <h2 class="text-xl font-bold text-gray-800">标题</h2></div>Tailwind 类名速查表
| 类别 | 类名示例 | 含义 |
|---|---|---|
| 文字大小 | text-sm / text-lg / text-2xl | 小 / 大 / 特大 |
| 文字颜色 | text-red-500 / text-gray-700 | 红色 / 深灰 |
| 文字粗细 | font-bold / font-normal | 粗体 / 正常 |
| 背景 | bg-white / bg-blue-100 | 白色 / 浅蓝 |
| 内边距 | p-4 / px-6 / py-2 | 四周 / 左右 / 上下 |
| 外边距 | m-4 / mt-2 / mb-8 | 四周 / 上方 / 下方 |
| 圆角 | rounded / rounded-lg / rounded-full | 小圆角 / 大圆角 / 圆形 |
| 阴影 | shadow / shadow-md / shadow-lg | 小阴影 / 中阴影 / 大阴影 |
| 布局 | flex / grid / hidden | 弹性 / 网格 / 隐藏 |
| 排列 | justify-center / items-center | 主轴居中 / 交叉轴居中 |
| 间距 | gap-4 / space-x-2 | flex 间距 / 水平间距 |
| 宽度 | w-full / w-1/2 / w-64 | 满宽 / 一半 / 固定宽度 |
| 响应式前缀 | md:flex / lg:text-xl | 中屏以上生效 / 大屏以上生效 |
| 状态 | hover:bg-blue-600 / focus:ring-2 | 鼠标悬停 / 获得焦点 |
命名规则总结:
- 方向:
t(top)b(bottom)l(left)r(right)x(左右)y(上下) - 大小:数字越大越大(
p-1<p-4<p-8) - 颜色:颜色名 + 深度(
gray-100最浅,gray-900最深)
不用背。AI 会自动选择合适的 Tailwind 类名。你只需要看到
bg-blue-500 text-white p-4时,知道这是”蓝色背景、白色文字、内边距 4”。
Part 3:JavaScript — 页面的行为
Section titled “Part 3:JavaScript — 页面的行为”JavaScript(简称 JS)让网页从”静态海报”变成”可交互应用”。用户点击按钮、输入文字、滚动页面时发生的所有事,都是 JS 在控制。
// 三种声明方式const name = "小明" // const — 不可变(推荐,AI 默认用这个)let count = 0 // let — 可变var old = "别用" // var — 旧写法,现在不推荐
// 常见数据类型const age = 25 // 数字const name = "小明" // 字符串const isAdmin = true // 布尔值const items = ["苹果", "香蕉"] // 数组(列表)const user = { name: "小明", age: 25 } // 对象(字典)// 传统写法function greet(name) { return "你好," + name}
// 箭头函数(AI 生成的代码几乎都用这种)const greet = (name) => { return "你好," + name}
// 单行箭头函数(更简洁)const greet = (name) => "你好," + name
// 调用greet("小明") // → "你好,小明"if (score >= 90) { console.log("优秀")} else if (score >= 60) { console.log("及格")} else { console.log("不及格")}
// 三元表达式(AI 经常用的简写)const result = score >= 60 ? "及格" : "不及格"// 条件 ? 真 : 假循环和数组操作
Section titled “循环和数组操作”const fruits = ["苹果", "香蕉", "橙子"]
// for 循环(传统方式)for (let i = 0; i < fruits.length; i++) { console.log(fruits[i])}
// forEach(遍历数组)fruits.forEach(fruit => console.log(fruit))
// map(把每项转换成新的东西,AI 最常用)const upper = fruits.map(f => f + "🍎")// → ["苹果🍎", "香蕉🍎", "橙子🍎"]
// filter(筛选)const long = fruits.filter(f => f.length > 2)// → ["苹果", "香蕉", "橙子"](中文都是两字,这里只是示例)
// find(找第一个符合条件的)const found = fruits.find(f => f === "香蕉")// → "香蕉"对象(最常用的数据结构)
Section titled “对象(最常用的数据结构)”const user = { name: "小明", age: 25, role: "admin"}
// 读取user.name // → "小明"user["role"] // → "admin"
// 修改user.age = 26
// 解构(AI 代码里非常常见)const { name, age } = user// 等价于:const name = user.name; const age = user.age;异步操作(网络请求)
Section titled “异步操作(网络请求)”前端经常需要向后端请求数据,这是异步操作——发出请求后不会傻等,而是继续做别的事,等数据回来了再处理。
// async/await 写法(最现代、最清晰)async function loadUsers() { const response = await fetch('/api/users') // 发请求,等响应 const data = await response.json() // 解析 JSON console.log(data) // 使用数据}
// 错误处理async function loadUsers() { try { const response = await fetch('/api/users') if (!response.ok) { // 状态码不是 200 throw new Error('请求失败: ' + response.status) } const data = await response.json() return data } catch (error) { console.error('出错了:', error) }}DOM 操作(直接控制页面元素)
Section titled “DOM 操作(直接控制页面元素)”// 找到元素const btn = document.getElementById('submit-btn')const items = document.querySelectorAll('.item')
// 修改内容btn.textContent = '加载中...'
// 监听事件(用户点击时执行某个操作)btn.addEventListener('click', () => { alert('你点击了按钮')})注意:在 React 项目中你几乎不会直接操作 DOM,React 会帮你管理。但了解 DOM 概念有助于理解 AI 写的代码。
Part 4:React — 现代前端框架
Section titled “Part 4:React — 现代前端框架”本课程前端使用 React。它不是一种新语言,而是用 JavaScript 写 UI 的一套组织方式。
核心思想:组件
Section titled “核心思想:组件”React 把页面拆成一个个组件,每个组件是一个独立的 UI 块。
整个页面├── Header 组件(导航栏)├── Sidebar 组件(侧边栏)└── Main 组件(主内容) ├── SearchBar 组件(搜索框) └── ExpenseList 组件(支出列表) ├── ExpenseItem 组件(单条支出) ├── ExpenseItem 组件 └── ExpenseItem 组件组件 = 一个返回 HTML 的函数
Section titled “组件 = 一个返回 HTML 的函数”// 最简单的组件function Welcome() { return <h1>欢迎回来</h1>}
// 接收参数的组件function Welcome({ name }) { return <h1>欢迎回来,{name}</h1>}
// 使用组件(像 HTML 标签一样)<Welcome name="小明" />{ } 里面可以写任何 JavaScript 表达式——变量、计算、函数调用都行。
JSX:在 JS 里写 HTML
Section titled “JSX:在 JS 里写 HTML”React 组件里的 “HTML” 其实是 JSX——一种让你在 JavaScript 里写 HTML 的语法。
function ExpenseItem({ category, amount, date }) { return ( <div className="flex justify-between p-4 border-b"> <div> <span className="font-bold">{category}</span> <span className="text-gray-500 ml-2">{date}</span> </div> <span className="text-red-500">-¥{amount}</span> </div> )}注意几个 JSX 和 HTML 的区别:
class→className(因为 class 是 JS 保留字)- 样式用 Tailwind 类名
{表达式}可以嵌入任何 JS 值
useState — 让组件有”记忆”
Section titled “useState — 让组件有”记忆””import { useState } from 'react'
function Counter() { const [count, setCount] = useState(0) // ^^^^^ ^^^^^^^^ ^ // 当前值 修改函数 初始值
return ( <div> <p>你点击了 {count} 次</p> <button onClick={() => setCount(count + 1)}> +1 </button> </div> )}useState 的规则:
- 调用
setCount(新值)→count变成新值 → 页面自动更新 - 不要直接改
count = 5,必须用setCount(5)
useEffect — 组件加载时做某件事
Section titled “useEffect — 组件加载时做某件事”import { useState, useEffect } from 'react'
function UserList() { const [users, setUsers] = useState([]) const [loading, setLoading] = useState(true)
useEffect(() => { // 这个函数在组件加载时自动执行 fetch('/api/users') .then(res => res.json()) .then(data => { setUsers(data) // 把数据存到状态 setLoading(false) // 加载完成 }) }, []) // [] 表示只执行一次(组件首次加载时)
if (loading) return <p>加载中...</p>
return ( <ul> {users.map(user => ( <li key={user.id}>{user.name}</li> ))} </ul> )}function LoginForm() { const [email, setEmail] = useState('') const [password, setPassword] = useState('')
const handleSubmit = async (e) => { e.preventDefault() // 阻止表单默认提交行为 const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }) const data = await response.json() // 处理登录结果... }
return ( <form onSubmit={handleSubmit}> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} {/* 输入时更新状态 */} placeholder="请输入邮箱" /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} /> <button type="submit">登录</button> </form> )}function Dashboard({ user }) { return ( <div> {/* 方式1:&& 短路 — 条件为真才渲染 */} {user.role === 'admin' && <AdminPanel />}
{/* 方式2:三元表达式 — 二选一 */} {user.isLoggedIn ? <Welcome /> : <LoginForm />}
{/* 方式3:提前 return */} {!user && <p>请先登录</p>} </div> )}function ExpenseList({ expenses }) { return ( <div> {expenses.map(item => ( <ExpenseItem key={item.id} // key 是必须的,用唯一标识 category={item.category} amount={item.amount} date={item.date} /> ))} </div> )}Part 5:三者如何配合
Section titled “Part 5:三者如何配合”一个完整的 React 组件示例
Section titled “一个完整的 React 组件示例”下面是一个”支出记录”页面的完整组件,把 HTML + CSS(Tailwind) + JS(React) 都用上了:
import { useState, useEffect } from 'react'
function ExpensePage() { // ---- JavaScript 部分:状态和逻辑 ---- const [expenses, setExpenses] = useState([]) const [total, setTotal] = useState(0)
useEffect(() => { fetch('/api/expenses') .then(res => res.json()) .then(data => { setExpenses(data) const sum = data.reduce((acc, item) => acc + item.amount, 0) setTotal(sum) }) }, [])
const handleDelete = async (id) => { await fetch(`/api/expenses/${id}`, { method: 'DELETE' }) setExpenses(expenses.filter(e => e.id !== id)) }
// ---- HTML + CSS(Tailwind) 部分:界面 ---- return ( <div className="max-w-2xl mx-auto p-6"> {/* 居中容器 */} <h1 className="text-2xl font-bold mb-4">支出记录</h1> {/* 标题 */}
<div className="bg-blue-50 p-4 rounded-lg mb-6"> {/* 汇总卡片 */} <p className="text-gray-600">本月总支出</p> <p className="text-3xl font-bold text-blue-600"> ¥{total.toFixed(2)} </p> </div>
<div className="space-y-2"> {/* 列表 */} {expenses.map(item => ( <div key={item.id} className="flex justify-between items-center p-3 bg-white rounded border hover:shadow-md transition"> <div> <span className="font-medium">{item.category}</span> <span className="text-gray-400 text-sm ml-2">{item.date}</span> </div> <div className="flex items-center gap-3"> <span className="text-red-500 font-bold">-¥{item.amount}</span> <button onClick={() => handleDelete(item.id)} className="text-gray-400 hover:text-red-500 text-sm" > 删除 </button> </div> </div> ))} </div> </div> )}分层理解这段代码
Section titled “分层理解这段代码”| 层 | 对应部分 | 做了什么 |
|---|---|---|
| JS 逻辑 | useState、useEffect、handleDelete | 管理数据、请求后端、处理删除 |
| HTML 结构 | div、h1、p、span、button | 定义页面有哪些元素 |
| CSS 样式 | Tailwind 类名 | 控制大小、颜色、布局、间距 |
三者混在一起写,但职责分明。看到 className="..." 就是样式,看到 {...} 就是逻辑,其余是结构。
读代码的技巧
Section titled “读代码的技巧”1. 先看 return,再看逻辑
Section titled “1. 先看 return,再看逻辑”React 组件的 return (...) 就是页面长什么样。先看 return 理解界面结构,再往上看逻辑。
2. 看不懂就问 AI
Section titled “2. 看不懂就问 AI”这段 React 代码在做什么?帮我逐行解释:
[粘贴代码]3. Tailwind 看不懂就查
Section titled “3. Tailwind 看不懂就查”看到一串不认识的类名,直接问:
Tailwind CSS 里 "flex justify-between items-center p-3" 分别是什么意思?4. 常见的 AI 生成代码模式
Section titled “4. 常见的 AI 生成代码模式”| 你看到的代码 | 它在做什么 |
|---|---|
useState([]) | 初始化一个空数组状态 |
useEffect(() => { fetch... }, []) | 组件加载时请求数据 |
{items.map(x => <Comp key={x.id} />)} | 循环渲染列表 |
{condition && <Component />} | 条件成立才显示 |
{a ? <A /> : <B />} | 条件为真显示 A,否则显示 B |
onChange={(e) => setValue(e.target.value)} | 输入框内容变化时更新状态 |
onSubmit={handleSubmit} | 表单提交时触发函数 |
className="flex ..." | Tailwind 样式 |
async/await + fetch | 请求后端 API |
| 技术 | 核心作用 | 你需要掌握到什么程度 |
|---|---|---|
| HTML | 定义页面有什么元素 | 看到 <div>、<input>、<button> 知道是什么 |
| CSS / Tailwind | 控制元素的样式 | 看到 bg-blue-500 p-4 知道是蓝色背景、有内边距 |
| JavaScript | 控制交互和逻辑 | 看懂变量、函数、if/else、map、async/await |
| React | 用组件化方式写 UI | 看懂 useState、useEffect、JSX、事件处理 |
你不需要写这些代码,AI 会帮你写。 但你需要:
- 看懂 AI 写了什么
- 判断结构和逻辑是否合理
- 发现明显错误时能告诉 AI 去改
下一步:回到主线,开始 Step 1:思考框架。