# HTML/CSS 布局基础
::: tip 🎯 核心问题
**网页是怎么做出来的？为什么有的网页只有文字，有的却像应用一样可以交互？** 这个问题会引出 Web 开发的三大基石，让你理解每一个网页背后的结构。
:::

---

## 1. HTML、CSS、JavaScript 分别是什么

### 1.1 从静态网页到动态应用

想象一下你在街上看到的**海报**。你只能看，不能互动——海报不会因为你看了就改变内容，也不会因为你点了某个地方就弹出更多信息。

早期的网页就是这样的"电子海报"：只能看、不能改、内容固定。

但现代网页完全不同了。它们像**桌面应用**一样：

- 你可以点击、拖拽、输入、上传
- 页面会根据你的操作实时变化
- 可以像软件一样完成复杂任务（比如在线视频剪辑）

**这种转变的核心原因，就是网页技术的三大基石：HTML + CSS + JavaScript**。

### 1.2 一个比喻：盖房子

| 技术           | 🏠 房子比喻              | 实际作用             | 具体例子                             |
| -------------- | ------------------------ | -------------------- | ------------------------------------ |
| **HTML**       | 房子的**结构和材料**     | 定义网页的内容和层级 | 这是一面墙、这是一扇窗、这是一个房间 |
| **CSS**        | 房子的**装修和外观**     | 控制网页的样式和布局 | 墙刷成蓝色、窗户放在东边、地板铺瓷砖 |
| **JavaScript** | 房子的**电器和智能系统** | 让网页具备交互和逻辑 | 按开关灯亮了、开门窗帘自动拉开       |

::: tip 💡 三者的关系

**HTML → CSS**：先有房子，才能装修。HTML 是基础，CSS 是美化。

**HTML + CSS → JavaScript**：先有房子和装修，才能装智能系统。JavaScript 会让"死"的页面变"活"。

**核心思想**：三者各司其职，缺一不可。只有 HTML 的页面很丑，只有 HTML+CSS 的页面不能互动，三者齐全才能做出像微信网页版、淘宝这样的"Web 应用"。
:::

### 1.3 动手试试看

👇 下面这个演示展示了 HTML/CSS/JavaScript 三者如何协作：

<WebTechTriad />

---

## 2. HTML：网页的骨架

### 2.1 需要 HTML的原理

在 HTML 出现之前，互联网上的内容只是**纯文本**。就像你现在看的这段文字，没有任何格式、没有层级、没有链接。

纯文本的问题是什么？

- ❌ **无法表达层级**：分不清哪是标题、哪是正文、哪是注释
- ❌ **机器看不懂**：搜索引擎、屏幕阅读器（盲人用）无法理解内容
- ❌ **无法交互**：没有链接、没有按钮、没有输入框

**HTML (HyperText Markup Language)** 就是为了解决这个问题诞生的。它用"标签"（tag）来标记内容的含义，让浏览器知道"这是什么"。

### 2.2 HTML 代码长什么样

HTML 的基本单位是"标签"（tag）。标签用尖括号 `< >` 包裹，成对出现：

```html
<h1>这是标题</h1>
<p>这是段落</p>
<a href="url">这是链接</a>
```

**关键概念**：

| 概念 | 解释 | 例子 |
|------|------|------|
| **标签** | 用尖括号包裹的标记 | `<h1>`、`</h1>` |
| **元素** | 标签 + 内容的整体 | `<h1>标题</h1>` |
| **属性** | 标签上的附加信息 | `href="url"`、`class="card"` |
| **嵌套** | 标签里再放标签 | `<div><p>文字</p></div>` |

### 2.3 看懂 HTML 代码的方法

::: tip 🎯 零基础必读：看代码的方法

很多新手看到一堆 `<xxx>` 就晕了。其实看 HTML 代码有**固定套路**：

**第一步：找"最外层"**

```html
<div class="card">        ← 这是容器，里面装着内容
  <h2>标题</h2>
  <p>描述文字</p>
</div>
```

**第二步：看标签名猜含义**

| 标签名 | 一眼记住 | 里面放什么 |
|--------|----------|------------|
| `<div>` | 大盒子 | 任何内容，用来分组 |
| `<span>` | 小盒子 | 文字片段，用来标记 |
| `<p>` | 段落 | 一段文字 |
| `<h1>`-`<h6>` | 标题 | 标题文字，数字越小越重要 |
| `<a>` | 锚点/链接 | 可点击跳转的内容 |
| `<img>` | 图片 | 不放内容，用 src 指向图片 |
| `<button>` | 按钮 | 可点击的文字/图标 |
| `<input>` | 输入框 | 不放内容，用户输入的地方 |

**第三步：看 class 和 id**

```html
<div class="user-card" id="user-123">
```

- `class="user-card"` → 这个元素的"类型"，CSS 可以批量选中
- `id="user-123"` → 这个元素的"身份证号"，唯一标识

**第四步：缩进表示层级**

```html
<body>
  <header>           ← 缩进表示 header 是 body 的孩子
    <nav>            ← nav 是 header 的孩子
      <a>首页</a>    ← a 是 nav 的孩子
    </nav>
  </header>
</body>
```
:::

### 2.4 常用 HTML 标签速查

**结构标签**（定义页面骨架）：

```html
<h1>这是一级标题</h1>
<h2>这是二级标题</h2>
<p>这是一个段落</p>
<div>这是一个容器（用来分组）</div>
<span>这是行内容器（用来标记文字）</span>
```

**链接与媒体**（让页面丰富）：

```html
<a href="https://example.com">点击这里跳转</a>
<img src="photo.jpg" alt="照片描述" />
<video src="movie.mp4" controls></video>
```

**表单**（收集用户输入）：

```html
<form>
  <input type="text" placeholder="请输入用户名" />
  <input type="password" placeholder="请输入密码" />
  <button type="submit">登录</button>
</form>
```

**语义化标签**（HTML5 新增，让页面含义更明确）：

```html
<header>页面头部</header>
<nav>导航栏</nav>
<main>主要内容区</main>
<article>一篇文章</article>
<aside>侧边栏</aside>
<footer>页脚</footer>
```

::: tip 💡 为什么要用语义化标签？

`<div class="header">` 和 `<header>` 看起来效果一样，为什么要用后者？

1. **SEO 友好**：搜索引擎能更好理解页面结构
2. **可访问性**：屏幕阅读器能快速定位"导航""主要内容"等区域
3. **代码可读性**：看到 `<header>` 一眼就知道是头部

**什么时候用 div？** 当没有合适的语义标签时。比如一个纯装饰性的容器。
:::

### 2.5 记住这么多 HTML 标签的方法

::: tip 🎯 新手困惑

"HTML 标签有一百多个，怎么记得住？"

**答案是：不需要全部记住。** 实际开发中，90% 的情况只用 20 个左右的标签。
:::

#### 按用途分类记忆

**一、页面结构类（画骨架）**

| 标签 | 记忆口诀 | 用途 |
|------|----------|------|
| `<header>` | 头 | 页面或区块的头部 |
| `<nav>` | 导航 | 导航链接区域 |
| `<main>` | 主体 | 页面主要内容（每页只有一个） |
| `<article>` | 文章 | 独立的内容块（可以单独拿走还有意义） |
| `<section>` | 章节 | 有主题的内容分组 |
| `<aside>` | 旁边 | 侧边栏、补充内容 |
| `<footer>` | 脚 | 页面或区块的底部 |

**记忆方法**：想象一张报纸——有报头（header）、目录（nav）、正文（main/article）、专栏（aside）、报脚（footer）。

**二、内容标记类（说清楚是什么）**

| 标签 | 记忆口诀 | 用途 |
|------|----------|------|
| `<h1>`-`<h6>` | 标题1-6 | 标题层级，h1 最大最重要 |
| `<p>` | 段落 | 一段文字 |
| `<ul>`/`<ol>`/`<li>` | 无序/有序/列表项 | 列表 |
| `<a>` | 锚点 | 链接，跳转用 |
| `<img>` | 图片 | 图片 |
| `<video>`/`<audio>` | 视频/音频 | 多媒体 |
| `<strong>`/`<em>` | 强调/斜体强调 | 语义化的强调 |

**记忆方法**：`<a>` 是 anchor（锚）的缩写，想象船抛锚停在一个地方，链接就是"停"到另一个页面。

**三、表单交互类（收集用户输入）**

| 标签 | 记忆口诀 | 用途 |
|------|----------|------|
| `<form>` | 表单 | 表单容器 |
| `<input>` | 输入 | 各种输入框（type 决定类型） |
| `<textarea>` | 文本区域 | 多行文本输入 |
| `<select>`/`<option>` | 选择/选项 | 下拉选择 |
| `<button>` | 按钮 | 按钮 |
| `<label>` | 标签 | 输入框的说明文字 |

**记忆方法**：`<input>` 的 type 属性决定它长什么样：
- `type="text"` → 文本框
- `type="password"` → 密码框
- `type="email"` → 邮箱框
- `type="checkbox"` → 复选框
- `type="radio"` → 单选框

**四、容器类（分组用）**

| 标签 | 记忆口诀 | 用途 |
|------|----------|------|
| `<div>` | 大盒子 | 块级容器，独占一行 |
| `<span>` | 小盒子 | 行内容器，只占内容宽度 |

**记忆方法**：div = division（分区），span = span（跨度）。div 用来划分大区域，span 用来标记文字片段。

#### 遇到不认识的标签怎么办？

**方法一：猜英文单词**

很多标签是英文单词的缩写：
- `<abbr>` = abbreviation（缩写）
- `<blockquote>` = block quote（块引用）
- `<caption>` = caption（标题/说明）
- `<figcaption>` = figure caption（图片说明）

**方法二：查 MDN**

[MDN HTML 元素参考](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element) 有所有标签的详细说明。

**方法三：问 AI**

> "HTML 中的 `<dl>` 标签是什么意思？什么时候用？"

#### 不用刻意背标签

**真正的工作流程是这样的**：

1. 你知道要用一个"容器" → 写 `<div>`
2. 后来发现这是"导航区域" → 改成 `<nav>`
3. 后来发现这是"独立文章" → 改成 `<article>`

**先写出来，再优化语义**。标签可以随时改，不用一开始就纠结用哪个。

---

## 3. CSS：网页的皮肤

### 3.1 需要 CSS的原理

想象你住进了一个**毛坯房**：有墙、有窗、有门，能住人，但是：

- 墙是灰色的水泥，不好看
- 插座和开关随便装，不美观
- 没有家具，生活不方便

只有 HTML 的网页就是这样：有内容、有结构，但**丑**、**乱**、**不友好**。

CSS (Cascading Style Sheets) 就是网页的"装修队"。它不改变 HTML 的结构（不拆墙、不改门），只负责：

- 🎨 **刷墙**：改变颜色、背景
- 🖼️ **挂画**：添加边框、阴影、圆角
- 🪑 **摆家具**：调整布局、间距、对齐

### 3.2 CSS 代码长什么样

CSS 代码有固定格式：

```css
选择器 {
  属性名: 属性值;
  属性名: 属性值;
}
```

**三种写法**：

```html
<!-- 方式一：行内样式（临时测试用） -->
<div style="color: red;">红色文字</div>

<!-- 方式二：内部样式（写在 HTML 文件里） -->
<style>
  .red-text { color: red; }
</style>

<!-- 方式三：外部样式（独立 CSS 文件，推荐） -->
<link rel="stylesheet" href="styles.css" />
```

### 3.3 看懂 CSS 代码的方法

::: tip 🎯 零基础必读：看 CSS 的方法

**第一步：看选择器——"给谁装修？"**

| 选择器 | 写法 | 含义 |
|--------|------|------|
| 标签选择器 | `p { }` | 所有 `<p>` 标签 |
| 类选择器 | `.card { }` | 所有 `class="card"` 的元素 |
| ID 选择器 | `#header { }` | 唯一的 `id="header"` 元素 |
| 后代选择器 | `.card h2 { }` | `.card` 里面的所有 `<h2>` |
| 组合选择器 | `.card, .box { }` | `.card` 或 `.box` 都选中 |

**第二步：看属性——"装修什么？"**

| 属性分类 | 常见属性 | 作用 |
|----------|----------|------|
| 文字 | `color`, `font-size`, `font-weight` | 颜色、大小、粗细 |
| 背景 | `background`, `background-color` | 背景色、背景图 |
| 边框 | `border`, `border-radius` | 边框线、圆角 |
| 间距 | `margin`, `padding` | 外边距、内边距 |
| 布局 | `display`, `flex`, `grid` | 排列方式 |

**第三步：看值——"装修成什么样？"**

```css
.card {
  width: 300px;        /* 固定宽度 */
  padding: 16px;       /* 内边距 16 像素 */
  border-radius: 8px;  /* 圆角 8 像素 */
  background: #fff;    /* 白色背景 */
}
```

**常见单位**：
- `px`：像素，固定大小
- `%`：百分比，相对于父元素
- `rem`：相对于根元素字体大小
- `vw/vh`：相对于视口宽度/高度
:::

### 3.4 选择器优先级

如果一个元素同时被多个选择器选中，谁说了算？

```html
<p class="highlight" id="special">这段文字是什么颜色？</p>
```

```css
p { color: red; }             /* 优先级：1 */
.highlight { color: yellow; } /* 优先级：10 */
#special { color: blue; }     /* 优先级：100 */
```

**答案**：蓝色。ID 选择器优先级最高，类选择器次之，标签选择器最低。

**内联样式**（写在 style 属性里）优先级是 1000，最高！

### 3.5 宽度对不上的原理

::: tip 🎯 真实场景

你做一个网页，要求三个卡片并排显示，每个卡片宽度 300px，容器总宽度 900px。你写了：

```css
.card { width: 300px; }
```

结果：**第三个卡片掉到下一行了！**

**为什么？** 因为 `width: 300px` 只是内容宽度，你忘了算 padding 和 border。如果卡片有 `padding: 20px` 和 `border: 1px`，实际宽度是 342px，三个卡片就是 1026px，超出了容器！
:::

每个 HTML 元素在 CSS 中都被看作一个"盒子"，由四层组成。想象你在**打包快递**：内容是商品，padding 是气泡膜，border 是纸箱，margin 是箱子之间的间隔。

👇 **动手试试看**：拖动滑块调节各层大小，观察盒模型的变化：

<CssBoxModel />

**解决方案**：

```css
.box {
  box-sizing: border-box;  /* 让 width 包含 padding 和 border */
  width: 200px;
  padding: 10px;
  border: 5px;
}
```

这样，`width: 200px` 就是最终宽度，padding 和 border 会"挤"在里面。

### 3.6 让元素自动对齐的实现

Flexbox 是现代 CSS 最常用的布局方式。它让元素自动排列对齐，就像书架上的书会自动对齐一样。

👇 **动手试试看**：切换方向、对齐方式，观察盒子如何排列：

<CssFlexbox />

**Flex 核心概念**：

| 属性 | 作用 | 常用值 |
|------|------|--------|
| `display: flex` | 开启 Flex 布局 | - |
| `flex-direction` | 主轴方向 | `row`（水平）、`column`（垂直） |
| `justify-content` | 主轴对齐 | `flex-start`、`center`、`space-between` |
| `align-items` | 交叉轴对齐 | `stretch`、`center`、`flex-start` |
| `flex-wrap` | 是否换行 | `nowrap`、`wrap` |
| `gap` | 元素间距 | `10px`、`1rem` |

### 3.7 CSS 预处理器：SCSS/SASS 与 LESS

::: tip 🎯 真实场景

你写了一个项目，CSS 文件有 2000 行。后来要改主题色，你发现：

- 主色调 `#3b82f6` 出现了 50 次
- 改一个颜色要全局搜索替换，还要担心漏改
- 选择器写成 `.nav .nav-list .nav-item .nav-link` 又长又难维护

**CSS 预处理器**就是来解决这些问题的。它让 CSS 也能"编程"：有变量、有嵌套、能复用代码。
:::

#### 3.7.1 什么是 CSS 预处理器？

**用人话解释**：预处理器是一种"更聪明的 CSS"。你用更强大的语法写样式，然后它帮你**编译**成普通 CSS，浏览器就能正常识别了。

**为什么要用？**

| 痛点 | 原生 CSS | 预处理器 |
|------|----------|----------|
| 颜色重复出现 | 到处复制粘贴 | 定义变量，一处修改全局生效 |
| 选择器层级太深 | 写成一长串 | 嵌套语法，层级一目了然 |
| 相同样式重复写 | 复制粘贴 | 混入（Mixin），像函数一样复用 |

#### 3.7.2 三大预处理器对比

| 特性 | 原生 CSS | **SCSS/SASS** | **LESS** |
|------|----------|---------------|----------|
| **变量写法** | `--primary` | `$primary` | `@primary` |
| **嵌套语法** | ❌ 不支持 | ✅ 支持 | ✅ 支持 |
| **混入（复用代码）** | ❌ 不支持 | ✅ `@mixin` | ✅ `.mixin()` |
| **学习难度** | 简单 | 中等 | 中等 |
| **流行程度** | - | ⭐⭐⭐ 最流行 | ⭐⭐ 较流行 |

**简单记忆**：
- **SCSS**：用 `$` 符号，Bootstrap 5 在用，生态最好
- **LESS**：用 `@` 符号，和 CSS 的 `@media` 写法一致，容易上手

#### 3.7.3 核心功能对比示例

##### 1. 变量：一处修改，全局生效

**场景**：主题色 `#3b82f6` 在 20 个地方用到，要改成红色。

<Tabs>
<TabItem label="原生 CSS">

```css
/* 要改 20 处，容易漏 */
.button { background: #3b82f6; }
.link { color: #3b82f6; }
.border { border-color: #3b82f6; }
```

</TabItem>
<TabItem label="SCSS">

```scss
$primary: #3b82f6;

.button { background: $primary; }
.link { color: $primary; }
.border { border-color: $primary; }
/* 改 $primary 一处即可 */
```

</TabItem>
<TabItem label="LESS">

```less
@primary: #3b82f6;

.button { background: @primary; }
.link { color: @primary; }
.border { border-color: @primary; }
/* 改 @primary 一处即可 */
```

</TabItem>
</Tabs>

##### 2. 嵌套：层级关系一目了然

**场景**：导航栏里有多层结构。

<Tabs>
<TabItem label="原生 CSS">

```css
/* 写成一长串，难看出层级关系 */
.navbar .nav-list .nav-item .nav-link { }
.navbar .nav-list .nav-item .nav-link:hover { }
```

</TabItem>
<TabItem label="SCSS">

```scss
.navbar {
  .nav-list {
    .nav-item {
      .nav-link {
        &:hover { }  /* & 表示父选择器 */
      }
    }
  }
}
```

</TabItem>
<TabItem label="LESS">

```less
.navbar {
  .nav-list {
    .nav-item {
      .nav-link {
        &:hover { }
      }
    }
  }
}
```

</TabItem>
</Tabs>

##### 3. 混入（Mixin）：复用代码片段

**场景**：多个按钮都需要"居中显示"的样式。

<Tabs>
<TabItem label="原生 CSS">

```css
/* 复制粘贴 3 次 */
.btn-primary {
  display: flex;
  justify-content: center;
  align-items: center;
}
.btn-secondary {
  display: flex;
  justify-content: center;
  align-items: center;
}
```

</TabItem>
<TabItem label="SCSS">

```scss
@mixin center {
  display: flex;
  justify-content: center;
  align-items: center;
}

.btn-primary { @include center; }
.btn-secondary { @include center; }
```

</TabItem>
<TabItem label="LESS">

```less
.center() {
  display: flex;
  justify-content: center;
  align-items: center;
}

.btn-primary { .center(); }
.btn-secondary { .center(); }
```

</TabItem>
</Tabs>

#### 3.7.4 如何选择？

| 情况 | 推荐选择 |
|------|----------|
| 刚开始学，项目小 | **原生 CSS**（先打好基础） |
| 项目用 Bootstrap 5 | **SCSS**（Bootstrap 源码是 SCSS） |
| 团队熟悉 `@` 符号 | **LESS**（和 CSS 的 `@media` 写法一致） |
| 需要复杂逻辑（循环、条件） | **SCSS**（功能更强大） |

#### 3.7.5 在项目中使用

**Vite 项目（最简单）**：

```bash
# 安装 sass
npm install -D sass

# 直接使用 .scss 或 .less 文件
```

::: tip 💡 新手建议

1. **先学好原生 CSS**：预处理器只是"语法糖"，不懂 CSS 基础会越用越乱
2. **小项目不用强上**：CSS 不到 200 行，直接写 CSS 更简单
3. **从 SCSS 开始**：语法和 CSS 几乎一样，只是多了 `$` 变量
4. **不要嵌套太深**：超过 3 层会让代码难维护
:::

#### 3.7.6 不同技术栈的文件组织对比

**同样的项目，用不同技术栈，文件结构有什么不同？**

<Tabs>
<TabItem label="原生 HTML + CSS">

```
my-website/
├── index.html              # 页面结构
├── about.html
├── css/
│   ├── reset.css           # 重置样式
│   ├── layout.css          # 布局样式
│   ├── components.css      # 组件样式
│   └── style.css           # 主样式（可能上千行）
├── js/
│   └── main.js
└── images/
    └── logo.png
```

**特点**：
- CSS 集中在一个或几个文件
- 改样式要来回切换 HTML 和 CSS 文件
- 样式容易互相冲突

</TabItem>
<TabItem label="Vue + 原生 CSS">

```
src/
├── components/             # 组件文件夹
│   ├── Button/
│   │   ├── Button.vue      # 模板 + 样式 + 逻辑
│   │   └── Button.test.js
│   ├── Header/
│   │   └── Header.vue
│   └── Footer/
│       └── Footer.vue
├── views/                  # 页面文件夹
│   ├── Home.vue
│   └── About.vue
├── App.vue                 # 根组件
└── main.js                 # 入口文件
```

**Button.vue 内部结构**：
```vue
<template>
  <button class="btn">点击</button>
</template>

<script>
export default { name: 'Button' }
</script>

<style scoped>              <!-- scoped 样式只影响当前组件 -->
.btn { background: #3b82f6; }
</style>
```

</TabItem>
<TabItem label="Vue + SCSS">

```
src/
├── assets/
│   └── styles/
│       ├── _variables.scss     # 变量：颜色、间距等
│       ├── _mixins.scss        # 混入：复用代码块
│       ├── _functions.scss     # 函数：颜色计算等
│       └── global.scss         # 全局样式入口
├── components/
│   ├── Button/
│   │   └── Button.vue          # 组件内用 @import 引入变量
│   └── Card/
│       └── Card.vue
├── views/
│   ├── Home.vue
│   └── About.vue
├── App.vue
└── main.js
```

**_variables.scss**：
```scss
$primary: #3b82f6;
$secondary: #64748b;
$spacing-sm: 8px;
$spacing-md: 16px;
```

**Button.vue**：
```vue
<style scoped lang="scss">
@import '@/assets/styles/variables';

.btn {
  background: $primary;      // 使用变量
  padding: $spacing-md;
}
</style>
```

</TabItem>
<TabItem label="Vue + Tailwind CSS">

```
src/
├── components/
│   ├── Button.vue          # 不需要 style 块
│   ├── Card.vue
│   └── Header.vue
├── views/
│   ├── Home.vue
│   └── About.vue
├── App.vue
└── main.js

# 配置文件（根目录）
tailwind.config.js          # 主题配置
tailwind.css                # 基础样式入口
```

**Button.vue**（没有 style 块）：
```vue
<template>
  <button class="bg-blue-500 hover:bg-blue-600 px-4 py-2 rounded">
    点击
  </button>
</template>
```

**特点**：
- 没有单独的样式文件
- 类名就是样式（`bg-blue-500` = 蓝色背景）
- 配置集中在 `tailwind.config.js`

</TabItem>
</Tabs>

**核心区别总结**：

| 技术栈 | 样式文件位置 | 主题管理 | 代码复用 |
|--------|-------------|----------|----------|
| 原生 HTML+CSS | 集中式 `css/` 文件夹 | 搜索替换 | 复制粘贴 |
| Vue + CSS | 分散在 `.vue` 组件内 | 搜索替换 | 复制粘贴 |
| Vue + SCSS | 组件内 + `styles/` 公共文件 | 变量统一管理 | 混入复用 |
| Vue + Tailwind | 无（类名里） | `tailwind.config.js` | 类名组合 |

### 3.8 记住这么多 CSS 属性的方法

::: tip 🎯 新手困惑

"CSS 属性有好几百个，怎么记得住？"

**答案是：按用途分类，记住核心属性，其他的用到再查。**
:::

#### 按用途分类记忆

**一、文字排版类（管文字长什么样）**

| 属性 | 记忆口诀 | 常用值 |
|------|----------|--------|
| `color` | 颜色 | `red`、`#fff`、`rgb(0,0,0)` |
| `font-size` | 字号 | `16px`、`1rem`、`1.5em` |
| `font-weight` | 字重 | `normal`、`bold`、`100`-`900` |
| `font-family` | 字体 | `"微软雅黑"`、`sans-serif` |
| `line-height` | 行高 | `1.5`、`24px` |
| `text-align` | 文字对齐 | `left`、`center`、`right` |
| `text-decoration` | 文字装饰 | `none`、`underline`、`line-through` |

**记忆方法**：想象你在 Word 里排版——改颜色、改大小、加粗、改字体、调行距、对齐、加下划线。

**二、盒模型类（管元素占多大空间）**

| 属性 | 记忆口诀 | 常用值 |
|------|----------|--------|
| `width`/`height` | 宽/高 | `100px`、`50%`、`100vw` |
| `padding` | 内边距 | `10px`、`10px 20px` |
| `margin` | 外边距 | `10px`、`auto`（居中用） |
| `border` | 边框 | `1px solid #ccc` |
| `border-radius` | 圆角 | `4px`、`50%`（圆形） |
| `box-sizing` | 盒模型 | `border-box`（推荐） |

**记忆方法**：padding 是"内"边距（内容到边框的距离），margin 是"外"边距（边框到其他元素的距离）。

**简写规则**：
```css
/* 四个值：上 右 下 左（顺时针） */
padding: 10px 20px 15px 25px;

/* 两个值：上下 左右 */
padding: 10px 20px;

/* 一个值：四个方向都一样 */
padding: 10px;
```

**三、背景与边框类（管元素长什么样）**

| 属性 | 记忆口诀 | 常用值 |
|------|----------|--------|
| `background` | 背景 | `#fff`、`url(bg.jpg)`、`linear-gradient(...)` |
| `background-color` | 背景色 | `#fff`、`rgba(0,0,0,0.5)` |
| `background-image` | 背景图 | `url(photo.jpg)` |
| `background-size` | 背景大小 | `cover`、`contain`、`100%` |
| `background-position` | 背景位置 | `center`、`top left` |
| `box-shadow` | 盒阴影 | `0 2px 10px rgba(0,0,0,0.1)` |
| `opacity` | 透明度 | `0`-`1`（0 完全透明） |

**记忆方法**：`background` 是简写，可以一次设置多个值：
```css
background: #fff url(bg.jpg) no-repeat center/cover;
/*          颜色  图片      是否重复   位置/大小 */
```

**四、布局类（管元素怎么排列）**

| 属性 | 记忆口诀 | 常用值 |
|------|----------|--------|
| `display` | 显示方式 | `block`、`inline`、`flex`、`grid`、`none` |
| `position` | 定位 | `static`、`relative`、`absolute`、`fixed`、`sticky` |
| `top`/`right`/`bottom`/`left` | 四个方向 | `10px`、`50%`（配合 position 使用） |
| `z-index` | 层级 | 数字越大越在上层 |
| `float` | 浮动 | `left`、`right`（老方法，不推荐） |
| `overflow` | 溢出处理 | `visible`、`hidden`、`scroll`、`auto` |

**position 记忆方法**：
- `static`：默认，正常流
- `relative`：相对自己原来的位置偏移
- `absolute`：相对最近的定位祖先元素定位
- `fixed`：相对视口定位（滚动也不动）
- `sticky`：滚动到一定位置后固定

**五、Flexbox 布局类（一维布局神器）**

| 属性 | 记忆口诀 | 作用 |
|------|----------|------|
| `display: flex` | 开启 Flex | 容器变成 Flex 容器 |
| `flex-direction` | 方向 | `row`（横向）、`column`（纵向） |
| `justify-content` | 主轴对齐 | 元素在主轴上怎么排 |
| `align-items` | 交叉轴对齐 | 元素在交叉轴上怎么对齐 |
| `flex-wrap` | 换行 | `nowrap`、`wrap` |
| `gap` | 间隙 | 元素之间的间距 |
| `flex` | 弹性 | 子元素的伸缩比例 |

**记忆方法**：
- `justify` = 证明/对齐 → 主轴对齐
- `align` = 排列/对齐 → 交叉轴对齐

**六、动画过渡类（管元素怎么动）**

| 属性 | 记忆口诀 | 常用值 |
|------|----------|--------|
| `transition` | 过渡 | `all 0.3s ease` |
| `transform` | 变换 | `translate(10px)`、`rotate(45deg)`、`scale(1.1)` |
| `animation` | 动画 | `fadeIn 1s ease forwards` |

**简写规则**：
```css
/* transition: 属性 时长 缓动函数 延迟 */
transition: all 0.3s ease 0s;

/* transform 可以组合多个变换 */
transform: translateX(10px) rotate(45deg) scale(1.1);
```

#### 遇到不认识的属性怎么办？

**方法一：猜英文单词**

很多属性是英文单词或缩写：
- `margin` = 边缘、余地
- `padding` = 填充
- `border` = 边界
- `visibility` = 可见性
- `cursor` = 光标

**方法二：按场景联想**

当你想实现某个效果时，想想"关键词"：

| 我想... | 可能的属性 |
|---------|------------|
| 改颜色 | `color`、`background-color`、`border-color` |
| 改大小 | `width`、`height`、`font-size` |
| 改位置 | `margin`、`position`、`top/left` |
| 改间距 | `padding`、`margin`、`gap` |
| 隐藏元素 | `display: none`、`visibility: hidden`、`opacity: 0` |
| 居中 | `margin: auto`、`text-align: center`、`justify-content: center` |
| 加圆角 | `border-radius` |
| 加阴影 | `box-shadow`、`text-shadow` |
| 加动画 | `transition`、`animation` |

**方法三：查 MDN 或问 AI**

[MDN CSS 属性参考](https://developer.mozilla.org/zh-CN/docs/Web/CSS/Reference) 有所有属性的详细说明。

> "CSS 中如何让文字只显示一行，超出部分用省略号？"

**方法四：用开发者工具"偷师"**

看到喜欢的网页效果：
1. 右键 → "检查"
2. 选中元素，看 Styles 面板
3. 直接复制 CSS 属性

#### 不用刻意背属性

**真正的工作流程是这样的**：

1. 你知道要"居中" → 搜索"CSS 居中"
2. 复制代码，改改数值
3. 用多了就记住了

**推荐的学习路径**：

1. **先掌握盒模型**：`width`、`height`、`padding`、`margin`、`border`
2. **再掌握 Flexbox**：`display: flex`、`justify-content`、`align-items`
3. **然后掌握定位**：`position`、`top/left`、`z-index`
4. **最后学动画**：`transition`、`transform`、`animation`

其他属性用到再查，用多了自然就记住了。

---

## 4. JavaScript：网页的大脑

### 4.1 需要 JavaScript的原理

只有 HTML + CSS 的网页，就像**商店橱窗里的模特**：

- ✅ 看起来很漂亮（CSS）
- ✅ 结构很清晰（HTML）
- ❌ 但你跟它说话，它不会回应
- ❌ 你按了按钮，什么也不会发生

**JavaScript** 让网页从"橱窗模特"变成"真人"：

- ✅ 点击按钮，会弹出提示
- ✅ 输入文字，会实时检查格式
- ✅ 滚动页面，会加载更多内容
- ✅ 提交表单，会显示"正在提交..."

### 4.2 JavaScript 代码长什么样

**能力一：记住数据**（变量）

```javascript
let userName = '张三'
let isLoggedIn = true
let cartCount = 5
```

**能力二：重复做事**（函数）

```javascript
function sayHello(name) {
  return '你好，' + name + '！'
}

console.log(sayHello('张三'))  // 输出：你好，张三！
```

**能力三：响应事件**（事件监听）

```javascript
button.addEventListener('click', function() {
  alert('按钮被点击了！')
})
```

**能力四：修改页面**（DOM 操作）

```javascript
document.getElementById('title').textContent = '新标题'
document.getElementById('box').style.background = 'red'
```

### 4.3 看懂 JavaScript 代码的方法

::: tip 🎯 零基础必读：看 JS 代码的方法

**第一步：找变量——"记住了什么？"**

```javascript
const API_URL = 'https://api.example.com'  // 常量，不会变
let count = 0                                // 变量，会变
const user = { name: '张三', age: 25 }       // 对象，多个数据
const items = ['苹果', '香蕉', '橙子']        // 数组，列表数据
```

**第二步：找函数——"能做什么？"**

```javascript
// 函数名通常能猜出用途
function handleClick() { }      // 处理点击
function fetchData() { }        // 获取数据
function validateForm() { }     // 验证表单
```

**第三步：找事件——"什么时候触发？"**

```javascript
button.addEventListener('click', handleClick)     // 点击时
input.addEventListener('input', validateForm)     // 输入时
window.addEventListener('scroll', loadMore)       // 滚动时
```

**第四步：找 DOM 操作——"改了什么？"**

```javascript
element.textContent = '新内容'     // 改文字
element.classList.add('active')    // 加样式类
element.style.display = 'none'     // 隐藏元素
parent.appendChild(child)          // 添加元素
```
:::

### 4.4 DOM：JavaScript 的页面操作方法

浏览器读取 HTML 代码后，不会把它们当成一堆字符串，而是在内存里把它们画成一棵"树"：

```
Document (文档)
    ↓
<html>
    ├─<head>
    │   └─<title>我的网页</title>
    └─<body>
        ├─<h1>欢迎</h1>
        └─<div class="card">
            ├─<img src="photo.jpg">
            └─<p>一段文字</p>
```

这棵树就叫 **DOM 树**。每个 HTML 标签都是这棵树上的一个"节点"。

**怎么找到节点？**

```javascript
// 按 ID 找（最快，唯一）
const element = document.getElementById('header')

// 按选择器找（最常用）
const element = document.querySelector('.card h2')    // 找第一个
const elements = document.querySelectorAll('button')  // 找所有

// 按关系找
element.parentNode           // 找父节点
element.children             // 找子节点
element.nextElementSibling   // 找下一个兄弟
```

**性能警告**：操作 DOM 是很**贵**的。每次修改 DOM，浏览器都要重新计算布局、重新绘制。

```javascript
// ❌ 低效：循环 1000 次，每次都操作 DOM
for (let i = 0; i < 1000; i++) {
  document.body.appendChild(createDiv())
}

// ✅ 高效：先拼好，一次性插入
const fragment = document.createDocumentFragment()
for (let i = 0; i < 1000; i++) {
  fragment.appendChild(createDiv())
}
document.body.appendChild(fragment)
```

这也正是 **Vue / React** 等现代框架诞生的原因：它们在内存里玩"虚拟 DOM"，计算好最小修改量，最后才去动真正的 DOM。

👇 **动手试试看**：DOM 操作的基本方法：

<DomManipulator />

### 4.5 ECMAScript：JavaScript 的版本演进

**ECMAScript** 是 JavaScript 的"标准说明书"。浏览器厂商按照这个标准来实现 JavaScript 引擎。

#### 为什么要有版本号？

JavaScript 不是一成不变的。每年都会新增功能、修复问题。版本号告诉你"这个浏览器支持哪些功能"。

#### 重要版本一览

| 版本 | 年份 | 核心特性 | 解决了什么问题 |
|------|------|----------|----------------|
| **ES5** | 2009 | 严格模式、`forEach`/`map`/`filter` | 规范化语言，增加数组方法 |
| **ES6/ES2015** | 2015 | `let/const`、箭头函数、`class`、`Promise`、模块化 | 最大的更新，现代 JS 的起点 |
| **ES2016** | 2016 | `includes()`、`**` 幂运算 | 小更新 |
| **ES2017** | 2017 | `async/await`、`Object.entries()` | 异步代码更易读 |
| **ES2018** | 2018 | `...` 扩展运算符、`Promise.finally()` | 对象和异步增强 |
| **ES2020** | 2020 | 可选链 `?.`、空值合并 `??`、`BigInt` | 安全访问嵌套属性 |
| **ES2021** | 2021 | `replaceAll()`、逻辑赋值 `??=` | 字符串和赋值增强 |
| **ES2022** | 2022 | 顶层 `await`、`.at()` 索引 | 模块异步加载更方便 |

#### ES6+ 最常用的新语法

**1. `let` 和 `const` 替代 `var`**

```javascript
// ❌ 旧写法：var 有变量提升，容易出 bug
var name = '张三'
if (true) {
  var name = '李四'  // 覆盖了外面的 name
}
console.log(name)  // '李四'，不是预期的结果

// ✅ 新写法：let 有块级作用域
let name = '张三'
if (true) {
  let name = '李四'  // 只在这个 if 里有效
}
console.log(name)  // '张三'，符合预期

// ✅ const：声明后不能重新赋值
const PI = 3.14159
PI = 3  // 报错！防止意外修改
```

**2. 箭头函数：更简洁的函数写法**

```javascript
// ❌ 旧写法
const add = function(a, b) {
  return a + b
}

// ✅ 新写法
const add = (a, b) => a + b

// 箭头函数的 this 绑定外层作用域
const obj = {
  name: '张三',
  // ❌ 普通函数：this 指向调用者
  oldWay: function() {
    setTimeout(function() {
      console.log(this.name)  // undefined
    }, 100)
  },
  // ✅ 箭头函数：this 继承自 obj
  newWay: function() {
    setTimeout(() => {
      console.log(this.name)  // '张三'
    }, 100)
  }
}
```

**3. 解构赋值：从对象/数组中提取数据**

```javascript
// 对象解构
const user = { name: '张三', age: 25, city: '北京' }
const { name, age } = user  // 直接提取
console.log(name)  // '张三'

// 数组解构
const colors = ['red', 'green', 'blue']
const [first, second] = colors
console.log(first)  // 'red'

// 函数参数解构
function greet({ name, age }) {
  console.log(`${name} 今年 ${age} 岁`)
}
greet(user)  // '张三 今年 25 岁'
```

**4. 模板字符串：字符串拼接不再痛苦**

```javascript
// ❌ 旧写法：一堆引号和加号
const msg = '用户 ' + name + ' 的年龄是 ' + age + ' 岁'

// ✅ 新写法：反引号 + ${}
const msg = `用户 ${name} 的年龄是 ${age} 岁`

// 还支持多行
const html = `
  <div class="card">
    <h2>${name}</h2>
    <p>年龄：${age}</p>
  </div>
`
```

**5. `async/await`：异步代码像同步一样写**

```javascript
// ❌ 回调地狱
fetchUser(function(user) {
  fetchOrders(user.id, function(orders) {
    fetchDetails(orders[0].id, function(details) {
      console.log(details)
    })
  })
})

// ✅ async/await
async function getUserData() {
  const user = await fetchUser()
  const orders = await fetchOrders(user.id)
  const details = await fetchDetails(orders[0].id)
  console.log(details)
}
```

**6. 可选链 `?.` 和空值合并 `??`**

```javascript
const user = {
  name: '张三',
  address: {
    city: '北京'
  }
}

// ❌ 旧写法：层层判断
const street = user && user.address && user.address.street
const streetName = street !== undefined ? street : '未知'

// ✅ 新写法：可选链 + 空值合并
const streetName = user?.address?.street ?? '未知'
```

::: tip 💡 如何知道浏览器支持哪些特性？

1. **查兼容表**：[caniuse.com](https://caniuse.com/) 输入特性名
2. **用构建工具**：Babel 可以把新语法转成旧浏览器支持的代码
3. **看目标用户**：如果只支持现代浏览器，大部分 ES6+ 特性都能直接用
:::

### 4.6 TypeScript：给 JavaScript 加上类型约束

#### 为什么需要 TypeScript？

**场景一：函数参数类型不确定**

```javascript
// JavaScript
function calculateTotal(price, quantity) {
  return price * quantity
}

calculateTotal(100, 5)      // 500 ✅
calculateTotal('100', 5)    // '1005' ❌ 字符串拼接，不是乘法
calculateTotal(100, '5')    // 500 ✅ 但这是运气好
```

JavaScript 不会告诉你参数类型错了，直到运行时才发现问题。

**场景二：对象属性拼写错误**

```javascript
// JavaScript
const user = {
  name: '张三',
  age: 25
}

console.log(user.nmae)  // undefined，拼写错误但不报错
```

**TypeScript 解决这些问题**：

```typescript
// TypeScript
interface User {
  name: string
  age: number
}

function greet(user: User) {
  console.log(`你好，${user.name}`)
  console.log(user.nmae)  // ❌ 编译时报错：属性 'nmae' 不存在
}

greet({ name: '张三', age: 25 })        // ✅
greet({ name: '张三', age: '25' })      // ❌ 编译时报错：age 应该是 number
greet({ name: '张三' })                 // ❌ 编译时报错：缺少 age
```

#### TypeScript 的核心概念

**1. 基本类型**

```typescript
let name: string = '张三'
let age: number = 25
let isActive: boolean = true
let anyValue: any = '可以是任何类型'  // 不推荐，失去类型检查的意义
```

**2. 接口（Interface）：定义对象结构**

```typescript
interface Product {
  id: number
  name: string
  price: number
  discount?: number  // 可选属性
  readonly createdAt: Date  // 只读属性
}

const product: Product = {
  id: 1,
  name: 'iPhone 15',
  price: 6999,
  createdAt: new Date()
}
```

**3. 类型别名（Type）**

```typescript
type ID = string | number  // 联合类型
type Status = 'pending' | 'approved' | 'rejected'  // 字面量类型

function updateStatus(id: ID, status: Status) {
  // ...
}

updateStatus(1, 'approved')      // ✅
updateStatus('abc', 'pending')   // ✅
updateStatus(1, 'processing')    // ❌ 'processing' 不是有效的 Status
```

**4. 泛型：可复用的类型**

```typescript
// 不用泛型：每个类型写一遍
function getFirstNumber(arr: number[]): number {
  return arr[0]
}
function getFirstString(arr: string[]): string {
  return arr[0]
}

// 用泛型：一个函数搞定
function getFirst<T>(arr: T[]): T {
  return arr[0]
}

getFirst([1, 2, 3])        // 返回 number
getFirst(['a', 'b', 'c'])  // 返回 string
```

#### TypeScript vs JavaScript 对比

| 特性 | JavaScript | TypeScript |
|------|------------|------------|
| 类型检查 | 运行时才发现错误 | 编译时就发现错误 |
| IDE 支持 | 基础提示 | 智能补全、重构、跳转定义 |
| 学习曲线 | 简单 | 需要学习类型系统 |
| 适用场景 | 小项目、原型 | 大型项目、团队协作 |
| 运行方式 | 浏览器直接运行 | 需要编译成 JavaScript |

#### 实际开发中的 TypeScript

```typescript
// API 响应类型定义
interface ApiResponse<T> {
  code: number
  message: string
  data: T
}

interface User {
  id: number
  name: string
  email: string
}

// 带类型的 API 请求
async function fetchUser(id: number): Promise<ApiResponse<User>> {
  const response = await fetch(`/api/users/${id}`)
  return response.json()
}

// 使用时 IDE 会提示所有属性
fetchUser(1).then(res => {
  console.log(res.data.name)   // ✅ IDE 自动补全
  console.log(res.data.nmae)   // ❌ 编译时报错
})
```

::: tip 💡 新手建议

1. **先学好 JavaScript**：TypeScript 是 JS 的超集，不懂 JS 学 TS 会很痛苦
2. **小项目不用强上 TS**：类型定义会增加代码量，简单项目反而变复杂
3. **从 JSDoc 开始过渡**：在 JS 文件里写 `/** @type {User} */` 注释，体验类型提示
4. **用 `any` 是妥协，不是解决方案**：遇到类型问题先尝试解决，不要直接 `any`
:::

### 4.7 现代 JavaScript 开发工具链

::: tip 🎯 为什么需要工具链？

浏览器只认识 HTML/CSS/JS。但现代开发中，我们会用：

- **TypeScript**：浏览器不认识，需要编译成 JS
- **SCSS/Less**：浏览器不认识，需要编译成 CSS
- **模块化**：`import/export` 需要打包成一个文件
- **新语法**：ES6+ 需要转译成旧浏览器支持的代码

工具链就是把这些"开发时用的代码"转换成"浏览器能运行的代码"。
:::

**核心工具**：

| 工具 | 作用 | 类比 |
|------|------|------|
| **Node.js** | JavaScript 运行环境 | 让 JS 可以脱离浏览器运行 |
| **npm/yarn/pnpm** | 包管理器 | 下载别人写好的代码库 |
| **Vite/Webpack** | 构建工具 | 把源代码打包成浏览器能运行的代码 |
| **Babel** | 编译器 | 把新语法转成旧语法 |
| **ESLint** | 代码检查 | 发现代码问题和风格不一致 |

**一个典型的开发流程**：

```bash
# 1. 初始化项目
npm create vite@latest my-app -- --template vue-ts

# 2. 安装依赖
cd my-app
npm install

# 3. 开发模式（热更新）
npm run dev

# 4. 构建生产版本
npm run build
```

---

## 5. 三者的协作关系

### 5.1 分工对比

| 角色 | 负责什么 | 不做什么 | 典型示例 |
|------|----------|----------|----------|
| **HTML** | 定义结构与语义 | 不负责样式/交互 | `<section><h1>标题</h1></section>` |
| **CSS** | 控制外观与布局 | 不负责逻辑/数据 | `.card { background: white; }` |
| **JavaScript** | 处理交互与逻辑 | 不负责结构定义 | `button.onclick = () => alert()` |

### 5.2 一个完整的协作示例

```html
<!DOCTYPE html>
<html>
<head>
  <style>
    /* CSS：让卡片好看 */
    .card {
      border: 1px solid #ddd;
      border-radius: 8px;
      padding: 16px;
      max-width: 300px;
    }
    .card button {
      background: #3b82f6;
      color: white;
      border: none;
      padding: 8px 16px;
      border-radius: 4px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <!-- HTML：定义卡片结构 -->
  <div class="card">
    <h2 id="title">点击按钮</h2>
    <button id="btn">点我</button>
  </div>

  <script>
    // JavaScript：让按钮能点击
    const btn = document.getElementById('btn')
    const title = document.getElementById('title')
    
    btn.addEventListener('click', function() {
      title.textContent = '已点击！'
      alert('标题已改变')
    })
  </script>
</body>
</html>
```

---

## 6. 不认识的代码故障排查

### 6.1 问 AI

> "HTML 中的 `<aside>` 标签是什么意思？什么时候用？"
> 
> "CSS 中的 `position: sticky` 是什么效果？"

### 6.2 查 MDN

[MDN Web Docs](https://developer.mozilla.org/) 是最权威的 Web 技术文档。遇到不认识的标签、属性、方法，直接搜索即可。

### 6.3 浏览器开发者工具

1. 右键点击页面元素 → "检查"
2. 在 **Elements** 面板看到 HTML 结构
3. 在 **Styles** 面板看到 CSS 样式
4. 在 **Console** 面板可以执行 JS 代码

### 6.4 常见 CSS 属性速查

| 看到这个 | 它是干嘛的 |
|----------|------------|
| `display: flex` | 开启弹性布局 |
| `position: absolute` | 绝对定位 |
| `z-index: 100` | 层级，数字大的在上面 |
| `overflow: hidden` | 超出部分隐藏 |
| `cursor: pointer` | 鼠标变成手型 |
| `transition: all 0.3s` | 动画过渡效果 |
| `box-sizing: border-box` | 让 width 包含 padding 和 border |

---

## 7. 名词速查表

| 名词 | 英文 | 用人话解释 |
|------|------|------------|
| **HTML** | HyperText Markup Language | 超文本标记语言，用标签描述网页结构 |
| **CSS** | Cascading Style Sheets | 层叠样式表，控制颜色、布局、动画 |
| **JavaScript** | JavaScript | 网页的编程语言，负责交互和逻辑 |
| **DOM** | Document Object Model | 文档对象模型，用对象树表示页面 |
| **Flexbox** | Flexible Box Layout | 一种一维布局方案，易于对齐与分布 |
| **盒模型** | CSS Box Model | 元素从内容到外边距的层层盒子 |
| **SCSS** | Sassy CSS | CSS 预处理器，支持变量、嵌套、混入 |
| **TypeScript** | TypeScript | JavaScript 的超集，增加了类型系统 |
| **ES6** | ECMAScript 2015 | JavaScript 的一个重要版本，新增很多语法 |
| **语义化** | Semantic HTML | 使用有含义的标签（如 header）而不是 div |
| **响应式** | Responsive Design | 页面自动适配不同屏幕尺寸的设计 |

---

## 总结

现在你已经知道：**HTML 定义骨架，CSS 负责颜值，JavaScript 赋予灵魂**。

这三者是 Web 开发的基石。理解了它们，你就能：

- 看懂任何网页的源代码（右键 → "查看网页源代码"）
- 修改别人的网页（浏览器 DevTools → Elements）
- 开始学习前端框架（Vue/React），它们都是基于这三者的

**下一步建议**：

- 如果你想快速做出网页，可以学习 **Vue** 或 **React** 框架
- 如果你想深入理解 CSS，可以学习 **Flexbox** 和 **Grid** 布局
- 如果你想提升代码质量，可以学习 **TypeScript**
