<!DOCTYPE html>必须独占第一行且前面不能有任何字符(包括空格、BOM、注释),否则浏览器触发怪异模式,导致盒模型错乱、Flex/Grid异常、document.body不可靠等硬性失效。

DOCTYPE 和 <meta charset="UTF-8"> 必须出现在第一行且位置不可错
浏览器一旦没在最开头看到 <!DOCTYPE html>,就会触发怪异模式——样式错位、盒模型异常、Flex/Grid 行为不一致,连 document.body 都可能读不到。这不是警告,是硬性失效。
常见错误现象:<meta charset="UTF-8"> 被塞进 <title> 后面、被注释包着、或放在 <body> 里;<!DOCTYPE html> 前有空格、BOM 字符、甚至 JS 注释。
- 所有 HTML 文件必须以
<!DOCTYPE html>开头,**前面不能有任何字符**(包括空格、换行、UTF-8 BOM) -
<meta charset="UTF-8">必须紧随<head>标签之后,且**必须在<title>之前** - 编辑器保存时务必选“UTF-8 无 BOM”编码,VS Code 默认可能带 BOM,需手动关掉
- CI 流程中可用
htmlhint --rule "doctype-first:true" --rule "meta-charset-require:true"自动拦截
语义标签不是装饰品,用错比不用更危险
<main> 出现两次、<section> 里只包一个 <p>、<nav> 塞了搜索框和登录按钮——这些不是“写得不够多”,是结构污染。屏幕阅读器会按语义跳转,搜索引擎会按语义加权,错用直接导致功能降级。
使用场景:CMS 模板动态插入标题时跳级;单页应用 JS 渲染后缺失 <h2> 导致 <section> 失去主题锚点;组件库封装时把 <aside> 当布局容器用。
立即学习“前端免费学习笔记(深入)”;
-
<main>全局唯一,且不能嵌套在<article>、<aside>、<nav>内 -
<section>必须自带可感知的主题,且应有<h2>–<h6>级标题(不可仅靠 CSS 视觉模拟) -
<aside>内容必须与邻近<article>或<section>存在逻辑关联(如“相关文章”),广告位请用<div role="complementary"> - DevTools 的「Accessibility」面板 > 「Heading level」树状视图,是验证层级连续性的最快方式
class/id 命名和属性书写是协作底线,不是风格偏好
团队里有人写 userCard、有人写 user_card、还有人直接 box1,CSS 就开始耦合、JS 查询 selector 开始失效、代码 Review 变成拼写检查。这不是细节问题,是协作契约失效。
容易踩的坑:disabled 写成 disabled="" 或直接省略;img 的 alt 居然留空但图片含关键信息;label 用 for 却没配 id,或 JS 动态生成 input 后忘了补 id。
- class 名强制
kebab-case(如search-input--disabled),禁用驼峰、下划线、纯数字 - 布尔属性必须显式赋值:
<input required="required">,而非<input required>(后者在某些 SSR 场景下会被序列化丢弃) -
<img>的alt:信息图填描述,装饰图写alt="",图标按钮必须带操作语义(如alt="下载 PDF") -
<label>必须通过for+id显式绑定,JS 动态创建时要同步生成匹配的id值
HTMLHint 不是锦上添花,是流程卡点
靠人工记住所有规则不现实。把校验塞进保存动作或 pre-commit 钩子里,才能让规范落地。否则每次 Code Review 都在重复指出 <div class="header"> 应该是 <header>,效率归零。
实操建议:
- VS Code 安装
HTMLHint扩展,配置.htmlhintrc启用核心规则:"tagname-lowercase"、"attr-lowercase"、"attr-value-double-quotes"、"id-unique" - Git hooks 中加入
npx htmlhint "**/*.html",失败则阻断 commit - 对模板类文件(如 EJS、Vue SFC 的
<template>)也要覆盖校验,HTMLHint 支持自定义后缀 - 别只信绿勾——
htmlhint报0 errors只代表语法合规,语义合理性仍需人工判断
真正难的从来不是写对标签,而是让所有人持续写对。工具能拦住 80% 的低级错误,剩下 20% 的语义判断,得靠每次 PR 里一句“这个 <section> 有独立标题吗?”来守住。



















