data-*属性须用dataset读取以获类型转换和驼峰命名;hidden语义化隐藏但不可替代css显隐控制;contenteditable需配合spellcheck与lang才完整可用;accesskey依赖tabindex可聚焦才生效。

HTML 元素的属性扩展不是“加点自定义字段”就完事了,关键在什么时候该用、怎么用才不破坏语义和可访问性,以及如何让 JavaScript 真正可靠地读取到你塞进去的数据。
data-* 属性必须用 dataset 读取,别直接 getAttribute
很多人写 <div data-user-id="12345" data-role="admin">,然后用 <code>el.getAttribute('data-user-id') 拿值——这能跑,但错失了 dataset 的自动转换能力。dataset 会把连字符转成驼峰(data-user-id → userId),还自动处理布尔/数字类型解析(如 data-active="true" 读出来是 true 而非字符串)。
- 正确写法:
el.dataset.userId或el.dataset['userId'] - 错误习惯:
el.getAttribute('data-user-id')—— 丢失类型推断,且大小写敏感易出错 - 注意:dataset 只反映初始 HTML 中声明的值;动态改
el.dataset.xxx = 'new'会同步更新 DOM 属性,但反过来手动 setAttribute 不会触发 dataset 更新
hidden 属性比 display: none 更语义,但不能替代 CSS 控制显隐逻辑
hidden 是全局布尔属性,设上就等效于 display: none,但它有明确的无障碍语义:屏幕阅读器会跳过它,搜索引擎也不索引内容。但它不是 CSS 替代品。
- 适用场景:临时隐藏某块内容(如加载中占位符、条件未满足的表单区块),且希望它彻底退出渲染流和可访问性树
- 慎用点:不要用它做「切换显隐」的主控开关,因为 JS 修改
el.hidden = false会强制覆盖所有 CSS 显示规则(哪怕你写了display: block !important) - 兼容性:IE 不支持,需降级用 class + CSS 控制
contenteditable 配合 spellcheck 和 lang 才算真正可用
只加 contenteditable 是半残废状态:拼写检查关着、语言没声明、焦点管理混乱。尤其多语言输入时,浏览器依赖 lang 决定词典和断字逻辑。
- 基础组合:
<div contenteditable spellcheck="true" lang="zh-CN"> <li>spellcheck="false" 不等于禁用编辑,只是关拼写提示;若想完全禁用交互,得加 <code>readonly或移除contenteditable - 注意:contenteditable 元素内嵌
<input>或<select></select>会行为异常,应避免混用 - 要让 accesskey 生效,至少得保证
tabindex="0"或显式设为正整数 - tabindex="0" 表示按 Tab 键可自然进入,-1 表示仅可通过脚本 focus(),不可 Tab 切入
- 实际项目中,accesskey 使用率极低,且容易和系统/浏览器快捷键冲突(如 Chrome 的 Ctrl+T),建议只在内部工具或无障碍增强场景谨慎启用
accesskey 和 tabindex 共存时 tabindex 优先级更高
accesskey 提供快捷键入口(如 accesskey="s" 对应 Alt+S),但它的激活依赖 tabindex 可聚焦。如果元素 tabindex="-1",accesskey 就失效。
真正难的不是写对属性名,而是判断某个功能该用原生属性驱动,还是该交给 CSS 类或 JS 状态管理——比如显隐控制,hidden 适合“永久性隐藏”,而 class="is-hidden" 更适合“视觉切换”。选错一层,后期维护成本翻倍。











