html语义化是渐进式增强的基石,是无障碍能力的起点;必须用原生语义标签而非div模拟交互,确保键盘导航、屏幕阅读器识别及aria正确关联,并配合css与js各守边界,保障关js、关css、纯键盘或语音环境下核心功能可用。

HTML语义化是渐进式增强的第一道防线
没有语义化的HTML,所谓“渐进式增强”就是空中楼阁。它不是锦上添花的装饰,而是所有无障碍能力的起点——屏幕阅读器靠<button></button>识别可交互元素,靠<label for="id"></label>关联输入框,靠<nav></nav>和<main></main>跳转区域。一旦用<div onclick>代替<code><button></button>,键盘用户就卡在Tab键上,ARIA属性也救不回来。
常见错误现象包括:表单提交后焦点丢失、语音命令无法触发操作、屏幕阅读器跳过关键控件。这些都不是JS或CSS的问题,而是HTML骨架塌了。
- 必须用
<input type="checkbox">而非自定义复选框DOM结构 -
<select></select>的每个<option></option>要有明确文本,不能靠JS动态注入空值再补 - 避免
role="button"包裹<div>——优先用原生<code><button></button> - 所有交互元素必须支持
Enter和Space键触发,这是原生标签默认行为,自定义组件需手动实现 - 不要在JSX里硬编码
id="email-input",而应始终使用fields.email.id - 当字段校验失败时,
aria-invalid="true"和aria-describedby必须同时生效,缺一不可 - 若使用Zod验证,
getZodConstraint()能自动提取minLength等约束,生成对应aria-valuemin等属性,别自己算 - 所有
hx-*属性必须搭配标准HTML属性(如action、method、type) - React表单中,
onSubmit事件处理器不能是唯一提交入口,<form></form>的action仍需有效 - 动态加载的内容(如搜索结果),必须有
aria-live="polite"容器包裹,否则屏幕阅读器不会播报变化 - 禁用
outline前,必须用:focus-visible配合清晰的替代轮廓(如box-shadow) - 避免用
pointer-events: none禁用交互,而应改用disabled属性或aria-disabled="true" - 响应式断点切换布局时,确保
tabindex顺序不被打乱(例如移动端折叠菜单后,焦点仍能自然进入)
表单字段的ID与ARIA关联不能靠手写
手动维护id、aria-labelledby、aria-describedby极易出错:ID重复、拼写不一致、错误消息未同步更新。Conform这类库的价值,正在于把这种机械劳动自动化——它通过useForm()生成唯一ID,并自动绑定fields.email.id到label htmlFor和input id,同时为错误区生成fields.email.errorId供aria-describedby引用。
你不需要记住哪段ARIA该配哪个ID,只需要确保调用链完整:label → input → error div → description div,全部由同一useField()返回的对象驱动。
JavaScript增强必须保留HTML fallback路径
htmx或Conform的“渐进式”体现在:它们不假设JS一定可用。比如一个<form hx-post="/login"></form>,其action="/login"属性就是纯HTML fallback;即使JS加载失败或被禁用,表单仍能提交并跳转——这是底线。
容易踩的坑是把“增强”当成“替代”:用hx-get实现搜索时,忘了写action和method,导致无JS环境直接失去搜索入口;或者用useForm()做客户端校验后,没配服务器端校验兜底,用户绕过JS就能提交非法数据。
样式层不能破坏语义结构或键盘焦点流
CSS不是“美化工具”,而是影响可访问性的关键变量。display: none会彻底移除元素的可访问性树节点,比JS隐藏更危险;visibility: hidden虽保留在DOM中,但多数屏幕阅读器仍会跳过;只有clip-path或position: absolute; left: -9999px这类“视觉隐藏但语义保留”的方式才安全。
另一个隐形陷阱是焦点管理:用outline: none抹掉默认焦点轮廓,却不提供替代样式,等于剥夺键盘用户的导航线索。这不是“设计感”,是可访问性断点。
真正难的不是写对一行ARIA,而是让每一层(HTML/CSS/JS)都守住自己的边界:HTML不越界管样式,CSS不越界管语义,JS不越界管基础功能。渐进式增强的复杂点,永远藏在“退一步还能用”这个简单要求里——它逼你反复验证:关掉JS、关掉CSS、只用键盘、只听屏幕阅读器,是否还能完成核心任务。











