电商商品列表必须用而非,因屏幕阅读器对仅读作“division”,而明确播报“列表,共n项”,支持快捷键逐项跳转;每个须有唯一id且含级标题,禁用包裹整表。

提升HTML可访问性不是靠堆ARIA属性补丁,而是从结构层就选对标签、写对关系、管住焦点——错一个基础点,后续所有优化都打折扣。
为什么<ul></ul>比<div>更适合商品列表
<p>屏幕阅读器对<code><div>只读作“division”,无法识别语义;而<code><ul></ul>会明确播报“列表,共N项”,用户可用快捷键(如J键)逐项跳转。
- 电商商品天然无执行顺序依赖,一律用
<ul></ul>,不用<ol></ol>
- 每个
<li>必须带唯一id(如id="product-1024"),否则键盘无法锚定到具体商品
-
<li>内必须含至少一个<h3></h3>或更高级标题(如商品名),不能只有图片和价格
- 禁止把整个列表塞进单个
<div class="product-grid">——这会让辅助技术误判为“长文”而非“可遍历集合”
<h3>
<code>label绑定失败的三种典型写法
<ul></ul>,不用<ol></ol>
<li>必须带唯一id(如id="product-1024"),否则键盘无法锚定到具体商品<li>内必须含至少一个<h3></h3>或更高级标题(如商品名),不能只有图片和价格<div class="product-grid">——这会让辅助技术误判为“长文”而非“可遍历集合”
<h3>
<code>label绑定失败的三种典型写法点击文字无法聚焦输入框、VoiceOver完全不读字段含义,90%以上源于label与input未建立浏览器可识别的关联。
- 正确方式:给
input设id,label用for显式指向它,如<label for="email">邮箱</label><input type="email" id="email"> - 避免隐式包裹:
<label>邮箱<input name="email"></label>在DOM动态更新或换行时易断开,iOS Safari和旧版TalkBack支持不稳定 - 禁用
aria-label或title替代label:它们不会触发点击聚焦,也不能被所有辅助技术解析为控件标签
fieldset+legend是表单分组的唯一可靠方案
仅靠CSS排版或<div>包裹成组字段,对屏幕阅读器毫无意义。用户需要知道“这一堆是干什么的”,而<code>fieldset+legend是所有主流辅助技术一致识别的分组机制。
-
legend必须存在且为纯文本,它是该组的“标题”,会被朗读两次(进入/离开时) - 不要嵌套
fieldset:多层嵌套在NVDA和JAWS中可能跳过中间层级,导致上下文丢失 - 移动端尤其依赖此结构:VoiceOver在“组模式”下会把整组当一个单元滑动,没有
legend等于没提供上下文
键盘焦点管理中最容易被忽略的硬约束
焦点跳转逻辑断裂,是导致屏幕阅读器用户卡死在某一步的根本原因。这不是“加个tabindex就行”的问题。
- 所有交互元素必须是原生可聚焦标签:
<button></button>、<a></a>、<input>等;用<div onclick>模拟按钮,就必须手动处理<code>tabindex="0"+keydown事件(回车/空格) - 步骤向导切换时,焦点必须自动落到新步骤的首个语义化元素(如
<h2></h2>或第一个<input>),不能留在旧位置让用户手动摸索 -
<main></main>必须是的直接子元素,且全页只能有一个;否则DOM结构异常,SSR渲染和辅助技术解析都会出错
真正难的不是记住这些规则,而是每次写<div>前下意识问一句:“它有没有不可替代的语义?有没有更原生的标签能直接表达这个意图?”——这个习惯一旦养成,可访问性就从补救变成本能。</div>











