语义化html是保障可访问性与机器可读性的基础,应优先使用等语义标签替代无意义的套娃,正确设置alt、/、for/id匹配及结构。

为什么 <div> 不该是第一个想到的容器
<p>很多人一想“要包一块内容”,立刻写 <code><div>,结果页面全是 <code><div class="wrapper"> 套娃。这不是错,但会丢失语义——搜索引擎和屏幕阅读器无法从中推断结构意图。
<ul><li>
<code><header></header> 用于页眉或区块头部,含 logo、主导航等;不是所有顶部区域都该用它,比如一个卡片标题就该用 <h2></h2> + <div>
<li>
<code><main></main> 在整个文档中只能出现一次,代表主体内容唯一入口;若页面有多个“主要内容区”(如仪表盘多卡片),说明结构设计有问题
<section></section> 必须自带标题(<h2></h2>–<h6></h6>),否则语义断裂;纯样式分组请继续用 <div>
<li>嵌套层级别太深:避免 <code><div><div><div>
<p>,优先用 <code>@#@#@#@#@#@#@#@#@#@0),图标本身可 alt=""
alt="图片"、alt="logo" 或留空不写——后者会导致屏幕阅读器读出文件名,非常混乱表格里 <th> 和 <code><td> 混用会带来什么实际问题
<p>表面看只是加粗/居中差异,但错误使用会让表格在无障碍场景下完全不可读。尤其当列数多、数据复杂时,屏幕阅读器依赖 <code><th> 的 <code>scope 属性定位上下文。
- 每张表必须有且仅有一个
<thead>,里面每个 <code><th> 都应带 <code>scope="col"(列头)或 scope="row"(行头)
- 合并单元格时,
colspan 和 rowspan 不能破坏行列对应关系;例如 <th colspan="2">成绩</th> 后,下一行两个 <td> 才算归属该表头
<li>避免用 <code><td> 冒充表头:即使加了 CSS 加粗,屏幕阅读器仍当它是普通数据单元格,不会作为导航锚点
<li>无标题表格(如纯布局用表)已淘汰多年,现代 CSS Grid/Flex 完全可替代,继续用属于技术债</li>
<h3>表单中 <code><label></label> 和 for/id 匹配失败的典型表现
<thead>,里面每个 <code><th> 都应带 <code>scope="col"(列头)或 scope="row"(行头)
colspan 和 rowspan 不能破坏行列对应关系;例如 <th colspan="2">成绩</th> 后,下一行两个 <td> 才算归属该表头
<li>避免用 <code><td> 冒充表头:即使加了 CSS 加粗,屏幕阅读器仍当它是普通数据单元格,不会作为导航锚点
<li>无标题表格(如纯布局用表)已淘汰多年,现代 CSS Grid/Flex 完全可替代,继续用属于技术债</li>
<h3>表单中 <code><label></label> 和 for/id 匹配失败的典型表现用户点击标签文字无法聚焦输入框,是这个错误最直接的后果。但更隐蔽的问题是:自动填充失效、语音控制失灵、测试工具报 ARIA 错误。
-
for值必须与目标<input id="xxx">的id完全一致(大小写敏感),且全局唯一;重复id会导致只绑定到第一个元素 - 嵌套式写法(
<label>用户名<input name="user"></label>)虽合法,但不利于复杂表单项(如带图标的输入框)和 JS 动态操作 - 复选框/单选按钮组必须用
<fieldset></fieldset>+<legend></legend>包裹,否则屏幕阅读器无法识别“这是一组相关选项” - 禁用
pointer-events: none或opacity: 0遮盖原生<input>的做法,会直接切断 label 绑定链路
语义不是“写得漂亮”的装饰,而是让 HTML 在脱离 CSS 和 JS 时仍能被机器和人正确解析。最容易被忽略的是:每次新增一个 <div> 或删掉一个 <code>alt,都在悄悄降低页面的鲁棒性。











