HTML 最容易被轻视:人人都会写几个标签,于是人人觉得自己会 HTML。我的转折点是第一次用 F12 看本站(这个 wiki 本身就是网页)的 DOM 树,顺着 <header>、<nav>、<main> 读下去,发现整页结构像一份排好版的文档大纲,而不是一堆 div 的乱炖。那一瞬间明白:HTML 的本职是描述「这是什么」,而不是「长什么样」,长什么样交给 CSS(第 2 章)。本章按「骨架 → 分类 → 语义 → 表单 → 无障碍」推进。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>页面标题</title>
</head>
<body>
<!-- 用户可见的内容全在这里 -->
</body>
</html>
每个成员都有明确的职责,漏了会出具体的事故:
<!DOCTYPE html>:声明 HTML5。省略它,浏览器进入怪异模式,盒模型的计算规则回到 2000 年代,布局莫名错位,而且报错信息不会提示你这个原因,是新手最冤的坑。<meta charset="UTF-8">:尽早出现,否则中文乱码(整页的「锟斤拷」)。<meta name="viewport">:移动端响应式的总开关,缺了它手机上字小如蚁、媒体查询(第 3 章)集体失效。lang="zh-CN":屏幕阅读器选发音、翻译工具选语言,都看它。head 里还住着 <link>(CSS)、<script>(JS,第 4 章)、favicon、SEO 用的 meta 描述,浏览器的标签页标题就是 title。
CSS 布局之前(第 3 章),先建立元素的「占位直觉」:
| 类别 | 占位行为 | 代表元素 |
|---|---|---|
| 块级 | 独占一行,可设宽高 | div p h1~h6 ul li section |
| 行内 | 不换行,宽高由内容决定(设了也常无效) | span a strong em code |
| 行内块 | 不换行,但可设宽高 | button input img |
用 DevTools 的 Elements 面板点选元素,右侧 Computed 面板能看到 display 的实际值,亲手确认这张表(img 的 display 是 inline 却能设宽高,因为它是替换元素,这类「表里不一」的案例正是亲眼看的价值)。
一个行内的经典陷阱:两个 <span> 之间源码里的换行和空格,渲染时会变成一个空格,排版「多了条缝」,和 CSS 无关,是 HTML 白空格折叠规则。知道这回事,排查时就不再怀疑人生。
HTML5 提供一组描述文档结构的标签,替代「通篇 div + class」:
<body>
<header>页头:logo、导航</header>
<nav>导航链接</nav>
<main>
<article>一篇独立内容(本 wiki 的每一章)</article>
<aside>侧边栏</aside>
</main>
<footer>页脚</footer>
</body>
语义化的收益不渲染时看不出差异(拿 div 全替掉,页面长得一样),它买的是三样东西:
<nav>「跳到导航」、靠 <main> 直达正文,div 全靠用户盲猜。<article> 比 <div class="article-box"> 直观得多。反直觉的一条:<div> 和 <span> 是「无语义容器」,它们不是坏东西,「纯布局的容器用 div」依然是正解(比如 purely 摆样式的一格),语义标签用在该用的结构上。别走极端到处 semantically 正确却多包八层。
<form action="/api/user" method="post">
<label for="email">邮箱</label>
<input type="email" id="email" name="email" required placeholder="you@example.com" />
<label for="age">年龄</label>
<input type="number" id="age" name="age" min="18" max="60" />
<textarea id="bio" name="bio" maxlength="200"></textarea>
<button type="submit">提交</button>
</form>
几个撑起日常的功能:input 的 type 自带校验(email/url/tel/number/date,浏览器自动弹「格式不对」的气泡)、required/min/max/maxlength/pattern 是原生约束、label 的 for 绑定让点文字也能聚焦输入框(可点击区域翻倍,移动端必做)。提交时,浏览器把有 name 的字段序列化成 name=value,GET 拼进 URL、POST 进请求体(发给谁、怎么发,计网课第 2 章 HTTP 的内容)。
记住一条安全铁律的因果:原生校验只是体验,不是防线。curl 一行命令就能绕过所有前端校验直打接口,后端校验(数据库课第 3 章的约束)才是真防线,前端校验的定位是「让好用户少踩坑」。
语义化本身就是无障碍的大头,再补三件举手之劳:图片必写 alt(图片挂了,alt 文字还在,这是它的第二个用途);表头用 <th scope="col"> 让读屏软件知道行列关系;别用 div + onclick 冒充按钮(键盘 Tab 到不了、回车按不动),按钮就 <button>。做完这三件,你的页面已经超过大半互联网。