文件上传必须保障可访问性:label需用for/id关联file input;拖拽区要tabindex="0"并同步调用input.click();dragover必须preventdefault();状态变更须用aria-live等语义属性主动通知。

label 必须用 for/id 关联 file input
原生 <input type="file"> 本身不可聚焦、不可键盘操作,label 是唯一标准的可访问性桥梁。只写文字不加 label,屏幕阅读器无法识别控件用途,键盘用户按 Tab 键也跳过它。
正确做法是:给 input 设 id,label 用 for 属性指向该 id。点击 label 文字等效于点击文件输入框,且支持空格/回车触发。
- 错误写法:
<input type="file" name="avatar"> 上传头像(无语义、不可访问) - 正确写法:
<label for="avatar-upload">上传头像</label><input type="file" id="avatar-upload" name="avatar"> - 若需隐藏原生按钮但保留可访问性,用
clip或position: absolute; clip: rect(0 0 0 0),别用display: none或visibility: hidden——那会让控件彻底从可访问树中消失
拖拽区必须支持键盘聚焦和空格触发
仅靠鼠标拖拽不满足 WCAG 2.1 标准。用户可能用键盘导航到拖拽容器,却无法用空格或回车打开文件选择器——因为隐藏的 <input type="file"> 没被正确调用。
关键点在于:拖拽容器要设 tabindex="0",并在 keydown 事件中监听空格/回车,并同步调用隐藏 input 的 .click()。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 不能在
setTimeout或 Promise 回调里调用.click(),浏览器会静默拒绝(非用户直接手势) - 必须确保
click()调用发生在事件处理函数同步上下文中,例如:event.key === ' ' || event.key === 'Enter' && event.preventDefault() && fileInput.click() - 拖拽容器需有明确焦点样式(如
outline),否则键盘用户不知道当前聚焦在哪
dragover 阻止默认行为是硬性要求,不是可选项
漏掉 e.preventDefault() 在 dragover 里,是拖拽上传失效的最常见原因。浏览器看到文件拖入页面却不阻止默认行为,就会尝试打开或下载文件,drop 事件根本不会触发。
这个行为和可访问性强相关:如果拖拽区没响应,键盘用户和屏幕阅读器用户会认为功能缺失或页面异常。
- 只需在
dragover中调用e.preventDefault(),drop里再调一次只是冗余 - 不要只监听
drop,也不要在dragenter里做文件校验——此时e.dataTransfer.files还不可靠,且dragenter可能频繁触发 - 移动端 Safari 对
dragover的兼容性较弱,若需全平台支持,建议 fallback 到点击上传,并显式标注“或点击选择文件”
aria 属性不能省,尤其是 aria-live 和 aria-invalid
文件上传涉及状态变化(如“已选 2 个文件”“类型不支持”“大小超限”),这些信息必须主动推送给辅助技术,不能只靠视觉提示。
用 aria-live="polite" 包裹状态区域,让屏幕阅读器在内容更新时自动朗读;表单验证失败时,给 input 加 aria-invalid="true" 并关联 aria-describedby 指向错误消息元素。
- 错误消息元素必须有
id,且与aria-describedby值一致,否则屏幕阅读器找不到上下文 - 不要用
title属性替代错误提示——它不被所有读屏器稳定支持,且无法键盘聚焦 - 拖拽高亮(如加
drag-over类)应配合aria-dropeffect="copy"和aria-grabbed="true"(虽现代读屏器支持有限,但属规范要求)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










