doctype 和 lang 必须顶格写在第一行,doctype 前不能有空格、bom 或注释,lang 值须符合 bcp 47 标准(如 zh-cn),多语言项目需 js 同步更新 document.documentelement.lang。

DOCTYPE 和 lang 必须顶格写在第一行
很多团队在模板生成或 CMS 输出时,会意外在 DOCTYPE 前插入空格、BOM 或注释,导致 IE、旧版 Safari 进入怪异模式(Quirks Mode),flex 布局失效、100vh 计算错误、<input type="date"> 直接不渲染。更隐蔽的问题是:部分构建工具(如某些版本的 Webpack HTML 插件)会在注入 title 前悄悄加空行。
实操建议:
-
DOCTYPE必须是文件绝对首字符,前面不能有任何内容(包括 UTF-8 BOM) -
lang属性值必须精确匹配 BCP 47 标准,中文站点用zh-CN,港澳台站点按实际用zh-HK、zh-TW等,lang="zh"或lang="cn"是无效值 - 多语言项目不能只靠静态 HTML,需在 JS 中同步更新
document.documentElement.lang
语义化标签不是“可选装饰”,而是结构契约
跨端团队常把 <nav></nav>、<main></main>、<section></section> 当成“锦上添花”,结果在小程序 WebView、PWA、屏幕阅读器中出现导航跳转失败、SEO 内容丢失、焦点顺序混乱。尤其 <main></main> 在单页应用中被重复使用,或嵌套在 <article></article> 里,直接触发 W3C 验证器报错且影响辅助技术识别主内容区。
实操建议:
-
<main></main>全局只能出现一次,且不能是<header></header>、<footer></footer>、<aside></aside>的子元素 - 导航区域必须用
<nav></nav>包裹,即使只有一组链接;纯视觉分隔线不用<nav></nav>,但带跳转功能的 tab 栏必须用 - 用
<time datetime="2026-07-01"></time>替代纯文本日期,让日历类 App、搜索引擎提取结构化时间
属性顺序和引号规则直接影响 JS 操作稳定性
不同端内核对属性解析宽容度不同:iOS WKWebView 对未加引号的 class=header 可能截断为 class=header 后跟空格,而安卓 X5 内核可能直接忽略;React/Vue 框架在 SSR 时若遇到 disabled 写成 disabled="disabled",可能与客户端 hydrate 不一致,引发 Hydration mismatch 错误。
实操建议:
- 所有属性值强制双引号,禁止省略或用单引号:
alt="公司Logo"✅,alt='公司Logo'❌,alt=公司Logo❌ - 布尔属性显式写完整值(如
required="required")或完全省略(required),避免混用;框架项目统一选后者 - 属性顺序按优先级排列:
class→id→data-→src/href→alt/title→role/aria-,便于快速扫描定位
图片 alt 和表单 label 是跨端无障碍底线
小程序审核、App Store 上架、政府网站验收都明确要求图片有有效 alt、表单控件有可关联 label。但团队常写 alt="" 一了百了,或用 for 指向不存在的 id,导致语音助手朗读“空白”、自动填充失效、测试工具报 critical error。
实操建议:
-
alt=""仅用于纯装饰图;图标按钮、操作 icon 必须描述功能,如alt="删除文章",而非alt="垃圾桶图标" -
<label></label>必须包裹输入控件,或通过for精确绑定对应id;禁用<div onclick="submit()"> 模拟按钮,改用 <code><button type="submit"></button> - CI 流程中接入 axe-core 或 Lighthouse CI,对
img[alt]、input:not([id]) + label类选择器做硬性检查
跨端 HTML 质量最难的不是写对某一行,而是让所有人——无论用 React、Vue、小程序原生还是纯 HTML 模板——在插入一个
<img> 或 <input> 时,条件反射写出 alt 和 label。规范落地的关键,是把检查点卡在提交前,而不是等上线后被审计打回。











