必须声明lang和charset:lang="zh-cn"确保屏幕阅读器正确朗读,charset="utf-8"须置于head最顶部防乱码;viewport必须含width=device-width和initial-scale=1.0;全页唯一且不可嵌套;语义标签需严格遵循结构契约。

必须声明 lang 和 charset,否则语义与编码都会失控
不写 lang="zh-CN",屏幕阅读器会用英文语音读中文,部分翻译插件识别错语言;不写 meta charset="utf-8" 或位置靠后,IE 和旧版 Safari 会触发乱码,且某些 CSS 字体 fallback 逻辑也会失效。
这两个属性不是“可选配置”,是浏览器解析 HTML 的启动开关:
-
lang必须精确到地区(如zh-CN、en-US),不能只写zh -
charset必须是utf-8,且必须放在最顶部(在<title></title>之前) - 不要用
http-equiv="Content-Type"这种冗余写法,HTML5 只认meta charset
viewport 设置错误等于放弃移动端渲染控制权
没加或写错 <meta name="viewport">,iOS Safari 和安卓 Chrome 就会按 980px 宽度渲染,再缩放显示——结果就是 1px 实际被拉伸成 2 物理像素、vh 计算失准、媒体查询完全失效。
正确写法只有一组确定组合:
-
width=device-width:让视口宽度 = 设备逻辑像素宽(如 iPhone 14 是 390px) -
initial-scale=1.0:禁用初始缩放,避免双击放大干扰布局 -
maximum-scale=1.0, user-scalable=no:生产环境必须加,防止用户误操作破坏表单或卡片对齐 - 绝对不要写
shrink-to-fit=yes(Safari 已废弃)或minimum-scale(引发 iOS 键盘弹起时页面错位)
语义标签不是“换个别名”,而是结构契约
把 <div class="header"> 改成 <code><header></header> 不等于完成语义化——<header></header> 是一个有隐式 ARIA role 的独立语义单元,浏览器和读屏器会据此构建导航树;而随意嵌套、跳级 heading、空 <section></section>,反而会造成语义污染。
关键约束点很具体:
-
<main></main>全页只能有一个,且不能出现在<header></header>、<footer></footer>或<aside></aside>内部 - 每个
<section></section>必须以<h2></h2>–<h6></h6>起始,且 heading 级别要严格递进(<h2></h2>→<h3></h3>,不可<h2></h2>→<h4></h4>) -
<nav></nav>只放导航链接集合,侧边“相关推荐”或“广告入口”不属于它 -
<footer></footer>可多层出现,但每层都应包含编辑时间、版权、关联链接等实质性元信息,不是纯样式容器
template 元素是唯一能规避跨平台 DOM 解析差异的原生方案
直接拼接 innerHTML += '<tr><td>...</td></tr>' 在 Safari、Firefox、Chrome 中表现不一:Chrome 自动补 <tbody> 并插入,Firefox 可能挂到 <code><table> 根节点下,Safari 甚至丢弃未闭合的 <code><td>。这不是 bug,是浏览器对缺失结构的容忍策略不同。
<p>用 <code><template></template> 就绕开了所有解析歧义:
-
<template></template>内容不执行脚本、不加载资源、不触发重排,是纯粹的离线 DOM 片段 - 克隆时用
content.cloneNode(true),得到的是结构 100% 可控的干净副本 - 所有样式必须写死在
<template></template>内(如style="min-width: 0"),不能靠 JS 运行时 patch —— Safari 14–15 的 Flexbox 塌陷问题就源于此 - 需要支持 IE?加一行 polyfill:
if (!HTMLTemplateElement) document.createElement('template');,但注意 IE 下content属性不可用
lang 缺失、viewport 错位、heading 跳级、innerHTML 拼接——这些不是小问题,是渲染链路里随时可能崩断的节点。











