lang属性必须设在标签上才有效,设在body或局部元素无效;data-*属性值均为字符串且dataset不响应变更;hidden与css隐藏混用易冲突;title/dir/accesskey不触发ui变化。

lang 属性只写在 body 或局部元素上无效
浏览器和辅助技术(如 VoiceOver、NVDA)只读取 标签的 lang 值来判断整页语言基调。改 document.body.lang 或某个 <div lang="ja">,对 SEO、自动翻译提示、字体 fallback、标点间距几乎没影响。
<p>常见错误现象:</p>
<ul>
<li>SPA 切换语言后,Chrome 翻译按钮不出现,或点了之后把中文翻成英文再翻回中文</li>
<li>VoiceOver 仍用旧语种朗读,哪怕 <code> 的 lang 已更新
实操建议:
- SSR 页面:服务端根据
Accept-Language头输出,别等 JS 加载后再补 - SPA 页面:语言切换时必须执行
document.documentElement.lang = "ja-JP",不是body,也不是只改 state - 静态多语言站:每个语言版本单独一份 HTML,
上硬编码对应值,避免 JS 注入延迟导致闪动 -
lang值必须符合 BCP 47:小写字母 + 连字符 + 地区码(可选),比如zh-CN、en-GB、ja-JP;zh_cn、ZH-CN、Chinese都无效
data-* 属性被当成响应式状态源引发类型错乱
dataset 只读取初始值,且所有值都是字符串——data-count="42" 读出来是 "42",不是数字;data-active="true" 是字符串 "true",不是布尔值。框架若直接拿它做响应式源,会错判类型、漏掉后续变更。
常见错误现象:
- React/Vue 组件 mount 后调用
el.setAttribute('data-id', '500'),但组件没重渲染 - 把
data-config='{"theme":"dark"}'当 JSON 解析,没加try/catch,JSON.parse()报错中断初始化 - SSR 渲染的 HTML 中
data-值被客户端 JS 覆盖,但框架没监听属性变化,导致首屏与 JS 状态不一致
实操建议:
- 需要动态状态,请用真实 state(React 的
useState、Vue 的ref),而非依赖dataset变更 - 若必须解析
data-*字符串,先校验格式:if (configStr && configStr.trim().startsWith('{')) { ... } - 自定义元素中可用
attributeChangedCallback桥接,但必须在static get observedAttributes()里声明(不含data-前缀)
hidden 和 class 混用导致隐藏逻辑冲突
hidden 是布尔属性,存在即生效,删掉就显示;但它和 class 控制的 display: none 或 visibility: hidden 不是同一层机制。两者同时作用时,CSS 可能覆盖 hidden 的默认行为,尤其在使用 CSS-in-JS 或 utility-first 框架时。
常见错误现象:
- 给元素同时加
hidden和class="opacity-0",结果元素仍占布局空间(hidden被 CSS 覆盖) - 用
element.hidden = false切换,但样式类没清理,导致视觉未恢复 - 旧版 Safari/IE 对
hidden支持不全,仅靠它做兼容性隐藏会失效
实操建议:
- 优先用
hidden控制语义化隐藏(不参与布局、不被屏幕阅读器读取),避免和 display 相关 class 混用 - 若需动画或渐变隐藏,改用
class+ CSS 过渡,不要依赖hidden - 兼容旧环境时,可 fallback:
el.hidden = false; el.style.display = '';,但注意不要污染内联样式
误用 title、dir、accesskey 触发 UI 变更预期
这些属性不驱动渲染、不触发重绘、不改变 DOM 结构,只影响提示、方向推断或快捷键绑定。指望它们“让页面变样”或“自动同步状态”,会白忙活。
常见错误现象:
- 给按钮加
title="提交表单",以为能替代aria-label,结果屏幕阅读器仍读按钮文本,不读 title - 设
dir="rtl"在<div> 上,发现文字没右对齐——因为 <code>dir只影响其子元素中 Unicode 强方向字符的排列起点,不强制 CSS 对齐 - 写
accesskey="s",但没测试是否和浏览器/系统快捷键冲突(比如 Chrome 的Ctrl+S保存) -
title是悬停提示,不是无障碍替代;需要语义化描述请用aria-label或aria-labelledby -
dir应设在语言切换最外层容器(如<article lang="ar" dir="rtl"></article>),避免嵌套层级过深导致方向推断混乱 -
accesskey必须配合视觉反馈(如焦点边框、高亮下划线),且上线前在主流浏览器+OS 组合中实测冲突情况
实操建议:
lang)只在根节点起效,有的(如 data-*)天生不可响应,有的(如 hidden)会被 CSS 覆盖——它们不是一套 API,只是碰巧都叫“全局属性”。











