纯HTML组件库默认不具备可访问性,因为<div>和<span>无语义、无键盘行为、不参与表单流程,屏幕阅读器仅读作“group”或“text”;用<div role="button">替代<button>会导致空格/Enter无效、:disabled不生效、焦点样式丢失。

为什么纯 HTML 组件库默认不具备可访问性
因为 <div> 和 <span> 没有语义、没有键盘行为、不参与表单流程,屏幕阅读器只会读作“group”或“text”,不会告诉你这是按钮、开关还是导航项。你写的 <div class="c-button">提交</div> 在辅助技术眼里和一段普通文字没区别。
常见错误现象:
- 用
<div role="button">替代<button>,结果空格/Enter 键无效、:disabled不生效、焦点样式丢失 - 卡片组件外层用
<div class="c-card">,导致 RSS 抓取失败、SEO 权重分散、视障用户无法识别内容边界 - 自定义下拉菜单没暴露
aria-expanded和aria-controls,屏幕阅读器无法告知当前状态
真正可访问的起点不是加 ARIA,而是选对原生标签:
- 独立内容单元 → 用
<article>(如商品卡片、用户评论) - 导航区块 → 用
<nav>,内部必须是<a>或<button> - 主内容区 → 用
<main>,且全页仅一个 - 图文说明 → 用
<figure><figcaption>,不是<div><div>
如何让自定义元素支持键盘与表单集成
注册 customElements.define('x-toggle', XToggle) 后,它默认仍是“哑巴节点”。要让它被读屏软件识别为开关、能响应空格键、能被 form.reset() 重置,必须满足三项硬性条件:
立即学习“前端免费学习笔记(深入)”;
- 构造函数第一行调用
super(),继承HTMLElement - 声明
static formAssociated = true(开启表单集成开关) - 在 Shadow DOM 内挂载真实
<input type="checkbox">,并通过 getter/setter 同步checked、disabled、value
attributeChangedCallback 是另一个高频翻车点:监听 checked 时,newValue 是字符串 "true" 或 null,不是布尔值。写成 input.checked = newValue === 'true' 才正确;disabled 则需判断 newValue !== null,因为 disabled="" 和 disabled="false" 都传 "",但后者不该禁用。
HTML 模板中 data-bind 的安全用法
<template id="c-card"> 里写 <h3 data-bind="title"></h3> 看似简单,但绑定逻辑若不严谨,会破坏可访问性:
- 禁止在
data-bind值里直接插入 HTML 字符串(XSS 风险),应只绑定原始类型:textContent赋值,innerHTML留给明确需要富文本的场景并手动转义 - 避免用连字符命名绑定点(如
data-bind="user-name"),JS 中访问需用el.dataset.userName,易拼错;推荐data-bind="user_name"或data-bind="userName" - 图片
<img data-bind="src">必须同步设置alt,否则生成的 DOM 会缺失替代文本——不能靠“后续补”
模板实例化时,必须用 document.importNode(tmpl.content, true),不是 cloneNode(true):前者保留 <input checked> 状态,后者会丢掉所有用户交互痕迹。
CSS 设计令牌对无障碍的实际影响
写死 margin: 8px 看似省事,但会导致三类可访问性失效:
- 高 DPR 屏幕(如 MacBook Retina)上像素模糊,视觉对比度下降
- 系统级缩放(Windows 125% / macOS Zoom)时,间距无法等比放大,布局崩坏
- 深色模式切换时,
!important会锁死颜色变量覆盖,导致主题色无法生效
正确做法是统一用 CSS 自定义属性:
:root {
--c-space-md: 0.75rem;
--c-color-text: #333;
--c-color-text-inverted: #fff;
}
.c-card__header { padding: var(--c-space-md); }
@media (prefers-color-scheme: dark) {
:root { --c-color-text: #ddd; }
}
所有组件内距、边框、阴影、字体大小都基于这些变量。禁用 px 和 !important 不是教条,而是确保下游项目能通过覆盖变量实现无障碍适配——比如把 --c-space-md 改成 1.25rem 以满足 WCAG 2.2 的间距要求。



















