data-、aria-、tabindex、hidden 四大全局属性需精准使用:data-仅存字符串且不可替代状态;aria-须严格同步语义与行为;tabindex=-1用于脚本聚焦,0加入Tab流;hidden原生控制可见性,优于CSS隐藏。

现代前端开发中,data-、aria-、tabindex、hidden 这四个全局属性用得最多,也最容易被误用或漏用——尤其在 React/Vue 组件封装、无障碍适配和动态 DOM 控制场景下。
为什么 data- 属性不能只当“存点字符串”用?
它本质是开发者自定义的语义容器,但很多人直接 el.dataset.foo = obj 导致序列化失败,或在 CSS 里用 [data-status="loading"] 却忘了属性值只能是字符串。
-
dataset自动把连字符转为驼峰(data-user-id→el.dataset.userId),但反向赋值不支持对象/数组,必须JSON.stringify后再存 - 服务端渲染(SSR)时,若框架未显式保留
data-属性(如 Next.js 默认 strip),运行时读不到原始值 - 不要用它替代状态管理:
data-loading="true"可以触发样式,但不该用来判断组件是否完成加载——应由真实 state 驱动
aria- 属性不是加了就等于可访问
加 aria-hidden="true" 却没同步隐藏视觉内容,或给 div 加 role="button" 却没处理 Enter/Space 键响应,反而会让屏幕阅读器更困惑。
-
aria-live的取值(polite/assertive)直接影响播报优先级;表单错误提示建议用assertive,而计数更新用polite -
aria-expanded必须与实际展开状态严格同步,React 中推荐用useEffect或useLayoutEffect更新,避免渲染间隙失真 - 原生语义标签(如
button、nav)自带隐式 ARIA,优先用它们,而不是给div硬加role
tabindex 值为 -1 和 0 的行为差异很关键
设 tabindex="-1" 能让元素被脚本聚焦(el.focus()),但无法通过 Tab 键到达;设 tabindex="0" 则按 DOM 顺序加入焦点流——这两者常被混用,导致键盘导航断裂。
立即学习“前端免费学习笔记(深入)”;
- 模态框打开后,应立即将焦点移到第一个可交互元素,并用
tabindex="-1"临时赋予非可聚焦元素(如标题)焦点能力 - 动态插入的 UI(如 Tooltip)若需键盘可达,必须显式设
tabindex="0",且确保其父容器未设tabindex="-1"阻断继承 - 避免对大量元素设正整数
tabindex(如tabindex="5"),会打乱自然 Tab 顺序,WCAG 明确不推荐
hidden 比 display: none 更适合逻辑控制
hidden 是 HTML 原生布尔属性,浏览器会自动忽略其子树的渲染、语音输出和焦点捕获,比 CSS 控制更彻底;但它不支持过渡动画,也不能被伪类(如 :not([hidden]))可靠选择。
- React 中直接写
{show && <div hidden="{!show}">...</div>}是错的——hidden是存在即生效,应写成<div hidden="{!show}">...</div>或更稳妥地用show ? ... : null - 服务端渲染时,
hidden属性会被保留并生效,而某些 CSS-in-JS 方案可能漏掉display: none的 SSR 样式注入 - 与
aria-hidden不同:hidden同时影响视觉、辅助技术和搜索引擎可见性;若只想隐藏给屏幕阅读器,该用aria-hidden="true"
真正难的不是记住这些属性怎么写,而是判断什么时候该用哪个——比如一个折叠面板的标题,需要 tabindex="0"、aria-expanded、aria-controls 三者配合,缺一不可;而加个 data-panel-id 只是为了方便 JS 查找,就不该承担状态或语义责任。



















