必须顶格写的三行是DOCTYPE、lang、charset,它们是浏览器解析HTML的启动开关:DOCTYPE须首行无空格/BOM/注释;lang须为zh-CN;charset须在head内前1024字节且为UTF-8。

全栈开发者写 HTML 时最容易忽略的不是语法对错,而是“浏览器怎么猜”——只要没写 lang、charset 或 DOCTYPE,现代浏览器就可能退化到怪异模式,JS 获取 offsetHeight 失准、input type="date" 直接不渲染、屏幕阅读器读错语种,这些都不是报错,而是静默失效。
必须顶格写的三行:DOCTYPE、lang、charset
这三行不是“可选配置”,是浏览器解析 HTML 的启动开关。顺序和位置错一个,后续所有结构都可能被误判。
-
DOCTYPE必须是文件第一行,前面不能有空格、BOM、注释;写成<!DOCTYPE html>,别用大写或带空格的变体 -
lang要写在<html>标签上,值按 IANA 注册标准来:简体中文站点用zh-CN,不是zh、cn或zh-ch -
charset必须出现在<head>最靠前的位置(建议第 1 或第 2 行),且只能是UTF-8(注意大小写和连字符),不能写成utf8、utf-8或UTF8
语义化标签不是“锦上添花”,而是 DOM 可靠性的基础
用 <div class="header"> 和用 <header> 渲染效果可能一样,但 JS 里 document.querySelector('header') 能稳定命中,而 querySelector('.header') 一旦别人改 class 名就断掉;SEO 抓取也只认语义标签层级,不认 class 名。
-
<main>全页只能有一个,且应包裹主体内容,不能嵌套在<article>或<section>内部 -
<nav>专指主导航,页脚链接、面包屑、分页控件不算;多个导航需加aria-label区分 -
<article>和<section>不可互换:<article>是可独立分发的内容单元(如博客正文),<section>是逻辑分组(如“评论区”、“相关推荐”)
闭合、大小写、引号:看似琐碎,实为协作底线
这些规则不产生新功能,但直接决定你写的 HTML 能不能被别人安全地改、能不能被自动化工具(如 HTMLHint、Prettier)识别、会不会在 SSR 或静态生成时出错。
立即学习“前端免费学习笔记(深入)”;
- 所有非自闭合标签必须显式闭合,哪怕浏览器能自动补全——
<p>text</p>不是可省略的“冗余”,而是防止<div><p>text</div>这类嵌套错乱的保险绳 - 标签名、属性名、class/id 值全部小写,
class="UserCard"或class="user_card"都违反规范;正确写法是class="user-card" - 所有属性值必须用双引号包裹,
class=user-card在某些构建工具或校验器中会直接报错,且data-id="123 abc"不加引号会导致截断
alt、role、aria-*:不是“无障碍加分项”,而是 HTML 合法性的一部分
缺少 alt 的 <img> 在 HTML5 中属于“验证失败”;滥用 role="button" 却没配键盘事件,会让屏幕阅读器宣布“按钮”却无法空格/回车触发——这不是体验问题,是代码语义错误。
-
<img>必须有alt:有意义的图写描述,纯装饰图写alt=""(空字符串,不是删掉属性) - 不要用
<div role="button">代替<button>;真要用 div 模拟,必须手动实现tabindex="0"、onkeydown和焦点管理 -
aria-*属性只在原生语义不足时补充,比如<ul>列表不需要aria-list,但动态加载的无限滚动区域需要aria-live="polite"
最常被跳过的其实是 lang 和 charset 的位置约束——它们不是“写了就行”,而是必须出现在前 1024 字节内,否则部分旧版 Safari 和 IE 会忽略。写完三行后,别急着写 <title>,先检查这两行有没有被注释或空格挤到第二行。










