Bootstrap组件默认支持基础ARIA但需手动完善:确保语义HTML、正确暴露交互状态(如aria-expanded)、补全role与label、保障颜色对比度≥4.5:1、焦点样式可见、动态内容同步更新ARIA属性。
Bootstrap默认组件对屏幕阅读器的支持程度
bootstrap 4+ 的大部分组件(如 alert、button、modal、dropdown)本身已内置基础 aria 属性,但「内置」不等于「开箱即用无障碍」。关键在于语义 html 是否被正确保留,以及交互状态是否被准确暴露。
- 比如
button元素自带可访问性,但若你用div+onclick模拟按钮,又没加role="button"和tabindex="0",屏幕阅读器就完全感知不到这是个可操作控件 -
Modal组件会自动加role="dialog"和aria-modal="true",但如果你手动移除了.modal-backdrop或禁用了焦点陷阱(focusTrap),键盘用户就可能卡在模态框外无法进入,或进入后无法关闭 -
Nav和Navbar默认没有role="navigation",需手动补上,否则屏幕阅读器不会将其识别为导航区域
表单控件必须配 label 或 aria-labelledby
Bootstrap 的表单样式常让人忽略语义标签——尤其是用 .form-control 包裹输入框时,容易直接写 <input type="text" class="form-control">,却漏掉关联的 label。这会导致屏幕阅读器读不出字段用途,甚至完全跳过该控件。
- 正确做法是:每个
input、select、textarea必须有显式label,且通过for和id关联(<label for="email">邮箱</label><input id="email" class="form-control">) - 若因布局限制无法使用视觉
label(如搜索框内嵌图标),则必须用aria-label或aria-labelledby提供文本替代(<input aria-label="搜索网站内容" class="form-control">) - Bootstrap 的
.form-check(复选框/单选)必须把label包住input,否则点击文字无法触发选中,且部分读屏会丢失关联关系
自定义组件或 JS 插件要手动补全 ARIA 状态
Bootstrap 自带的 JS 插件(如 Tooltip、Popover、Carousel)虽加了部分 ARIA,但动态状态(如展开/收起、当前页码、悬停提示是否显示)仍需开发者干预。尤其当用 JS 动态切换内容时,ARIA 属性不会自动更新。
-
Tooltip默认只在触发时临时插入 DOM,不持久渲染,因此aria-describedby指向的元素可能不存在——应确保 tooltip 内容在 DOM 中存在,或改用aria-live="polite"区域播报变化 -
Carousel必须提供「当前第 X 页 / 共 Y 页」的实时播报,仅靠aria-live不够,还需用aria-current="true"标记当前项,并给轮播容器加role="region"和aria-label="图片轮播" - 所有通过
data-bs-toggle控制显隐的组件(如折叠卡片),都要同步控制aria-expanded值——Bootstrap 不会自动帮你同步这个属性,得自己用事件监听补上
颜色对比度与键盘焦点可见性不是 Bootstrap 责任
Bootstrap 的默认配色(如浅灰文字 #6c757d 在白底上)对比度只有 ~4.2:1,低于 WCAG AA 要求的 4.5:1;其焦点样式(:focus)在部分版本中被重置为极细虚线甚至透明,导致键盘用户完全看不到当前焦点位置。
- 必须检查所有文本颜色组合,用工具(如 axe DevTools 或 WAVE)验证对比度,必要时覆盖
$body-color、$secondary等 Sass 变量 - 务必重置
*:focus和*:focus-visible样式,至少保证 2px 实线、高对比色块(如outline: 2px solid #0d6efd),并避免用outline: none全局清除 - 响应式断点切换时,隐藏/显示的内容要同步处理
aria-hidden——例如移动端折叠的导航菜单,展开时得设aria-hidden="false",否则读屏仍会跳过
最常被忽略的是:ARIA 属性和焦点管理必须随 JS 状态实时更新,而不是只在初始化时写一次。静态写死的 aria-expanded="false" 在用户点击后依然为 false,等于没写。


















