HTML全局属性是前端交互与无障碍的底层开关:data-*需按驼峰规则访问dataset;contenteditable不触发input事件,应监听beforeinput或用capture+防抖;hidden影响布局与可访问性,非仅视觉隐藏;tabindex负值控制程序化聚焦但不入Tab流。

HTML全局属性不是装饰品,而是前端交互的底层开关——用错一个,JS逻辑可能失效,无障碍体验直接归零。
为什么data-*不能直接当变量名用
你写<button data-user-id="123">删除</button>,然后在JS里想直接user.id取值?不行。浏览器不会自动把data-user-id转成userId变量名,它只是存进dataset对象里,且规则固定:连字符转驼峰、全小写开头。
- 正确读法:
el.dataset.userId(不是el.dataset.user-id或el.dataset.Userid) - 写入时也得按规则:
el.dataset.userId = "456"→ DOM中自动变成data-user-id="456" - 注意大小写:HTML里写
data-UserId,JS里dataset.userid会是undefined,因为解析只认小写+连字符组合 - 别存敏感数据:
data-token这种字段可能被爬虫或调试工具轻易看到,后端校验不能省
contenteditable开启后,input事件根本不会触发
这是最常踩的坑:给<div contenteditable>绑input事件,发现打字没反应。因为contenteditable元素不触发input,它触发的是beforeinput和compositionstart/end——尤其在中文输入法下,input事件只在“确认输入”后才发一次,中间选词过程完全静默。
- 监听
beforeinput能捕获每次按键/粘贴/删除,但兼容性差(Safari 16.4+才稳定) - 稳妥方案:用
addEventListener('input', handler, { capture: true })并配合setTimeout防抖,因为contenteditable的input虽延迟但最终会发 - 别忘了
spellcheck="false",否则移动端双下划线干扰编辑体验 - 如果要双向绑定,别直接改
innerHTML,用textContent更安全,避免XSS和格式错乱
hidden和display: none不只是“看不见”的区别
很多人以为hidden就是display: none的语义化写法,其实它影响布局计算、可访问性树、甚至打印样式。
立即学习“前端免费学习笔记(深入)”;
-
hidden元素不渲染、不占空间、不触发focus、不被屏幕阅读器朗读(除非加aria-hidden="false") -
hidden="until-found"是新值(Chrome 122+),表示“等首次被JS显式设置为hidden=""前,仍参与布局”,适合渐进式加载场景 - 用CSS隐藏时,
visibility: hidden仍占位,opacity: 0还能被聚焦和点击——hidden则彻底移出渲染流 - 服务端渲染时,
hidden会被保留到HTML里,而style="display:none"容易被JS覆盖导致闪现
tabindex设成负数时,键盘焦点能进去,但focus()调不了
tabindex="-1"让元素可被el.focus()聚焦,却不能通过Tab键到达——这特性常被用来实现“程序化聚焦但不破坏Tab顺序”,但容易误用。
-
tabindex="0":加入自然Tab流,可Tab进入也可focus() -
tabindex="-1":不能Tab进入,但能focus(),适合模态框打开后手动聚焦首元素 -
tabindex="999":强行插队Tab流,破坏可访问性,绝对别用 - 动态增删
tabindex时,记得同步更新aria-hidden,比如菜单收起时给子项加tabindex="-1"和aria-hidden="true"
真正难的不是记住每个属性怎么写,而是判断什么时候该用data-而不是dataset,什么时候该用hidden而不是aria-hidden——边界模糊处,往往就是bug藏身的地方。



















