可访问性修复核心在四点:图片alt需描述功能而非文件名;表单label必须显式关联控件;语义结构(main/nav等)须合法唯一;动态内容须用aria-live通知。

可访问性问题不是“加个 aria-label 就完事”,90% 的修复集中在四个点:图片 alt、表单 label 关联、语义结构(如 main、nav)、动态内容通知(aria-live)。改对这四块,读屏工具立刻能识别,键盘用户马上可操作。
图片 alt 属性缺失或写成文件名
屏幕阅读器遇到没 alt 的图片直接跳过;写成 alt="icon-search.png" 或 alt="blue-button" 会让用户完全不知道功能。
-
alt=""只用于纯装饰图(比如背景花纹、分隔线) - 功能图标必须写用途:
alt="搜索"、alt="关闭弹窗",不是“叉形按钮” - 带链接的图片,
alt描述目标而非图像本身:alt="查看产品详情" - SVG 内联时,需配合
<title>和aria-hidden="true"(若已有<title>)或role="img" - 旁边已有相同文字说明时,
alt=""比重复写更合适
表单控件没绑定 label 或用 placeholder 充数
仅靠视觉对齐或 placeholder,键盘用户和读屏软件根本不知道这个输入框是干啥的。焦点落在 <input> 上时,没有可访问名称,就等于“哑巴字段”。
- 首选包裹式:
<label>邮箱<input type="email"></label>—— 天然关联、点击聚焦、无需额外属性 - 分离布局必须配对:
<label for="email">邮箱</label><input id="email" type="email">,且id值不能重复、不能含空格或特殊字符 -
placeholder不是标签,它不提供持久可访问名称,且输入后消失,对比度常不达标 - 禁用
title替代label:部分读屏不支持,也不参与焦点逻辑 - 自定义复选框/单选按钮,必须同步维护
aria-checked和键盘焦点管理
语义结构崩坏:main 多余、header/nav 替换后样式全丢、p 里嵌 div
浏览器对非法嵌套静默修正(比如 <p><div>xxx</div></p>),会直接关掉 <p>,把 <div> 扔到外面——你写的 aria-labelledby 关系瞬间失效。
使用 Puppeteer + Chrome 将 HTML 渲染为中文 PDF,自动处理图表等待、Tab 展开、动画、测高、白边消除、防分页,适用于看板、报表、网页和交互图表转 PDF。
立即学习“前端免费学习笔记(深入)”;
-
<main>必须全局唯一,且只包用户真正要操作/阅读的核心内容(如文章正文、商品列表);塞进 banner、侧边栏或广告会导致跳过或定位错误 - 用
<header>替换<div class="header">后样式丢失?不是 CSS 不兼容,是选择器没覆盖新标签——把.header改成header,或扩写为header, .header - 浮动清除规则(如
.clearfix::after)对<nav>无效,得加nav { display: flow-root; }或保留 class - 检查 DOM 是否被浏览器“修过”:在 Console 运行
document.body.innerHTML,和源码逐行比对;多出的</p>或消失的嵌套就是证据
iframe 缺 title、动态内容无 aria-live、错误消息 display: none 隐藏
未设 title 的 <iframe> 在 VoiceOver/NVDA 中只会报“框架”或“无标题框架”,用户无法预判内容类型,极易跳过关键交互区域(如嵌入登录弹窗、地图)。
-
<iframe>必须有描述性title,如title="嵌入的地图:查找附近门店" - AJAX 提交成功、校验失败、模态框打开等变化,必须用
aria-live="polite"包裹错误提示,并放在 DOM 靠前位置(最好紧贴<form>开头) - 模态框需同时设置
role="dialog"、aria-modal="true"和aria-labelledby指向标题元素 - 校验失败字段,除视觉高亮外,必须加
aria-invalid="true"和aria-describedby指向错误消息id - 禁用
display: none隐藏错误消息:它会从可访问树中彻底移除内容;用visibility: hidden或opacity: 0+position: absolute更稳妥
最容易被忽略的是 DOM 结构是否真如你所写——浏览器自动“修”HTML 的行为,常让 aria-labelledby、aria-describedby 等依赖父子关系的属性彻底失效。别只信编辑器里的代码,要查 document.body.innerHTML,要右键 DevTools 里父容器 → “Edit as HTML” 删个空格再回车,看子节点是否整体跳出。


















