B04 全局属性与交互元素

2026-10-31 14:550 阅读约 11 分钟HTML

摘要:id、class、hidden、data-* 这类属性可以写在任何标签上,因此最容易被滥用:id 重复、class 承担语义、hidden 代替删除。HTML 还内置了三类交互元素——折叠、弹层、进度条,用原生元素可以省掉一大段脚本与无障碍处理。本文给出全局属性的使用边界与三类原生交互元素的写法。
关键词:全局属性,data 属性,details,dialog,原生化

所属:frontend/html / B-进阶 | 上一篇:B03-内嵌内容与安全 | 下一篇:B05-结构化数据

1 引言

同一份页面里,class 常被同时当作样式钩子与语义标记,id 常被复制粘贴出重复值。这类问题不会立刻报错,却会让脚本选择器与无障碍关联失效。

本文按「标识类 → 状态类 → 数据类」整理全局属性,再给出三类可替代脚本的原生交互元素。范围见表 1-1。

项 本文覆盖 本文不覆盖
全局属性 id、class、hidden、lang、dir、data-*、tabindex、contenteditable ARIA 属性(C 阶段)
交互元素 details/summary、dialog、progress/meter 复杂组件与状态管理
脚本 仅在必需处用少量脚本控制弹层 框架与组件库

2 预备知识

项 要求 核对方式
环境 A02 的本地服务器 能访问 localhost
文件 html-practice/attrs.html 编码 UTF-8
浏览器 Chrome 130+,开发者工具 Console 可用 能执行选择器表达式
前置 A08 语义骨架已掌握

3 原理与实现

3.1 全局属性的三类职责

全局属性按职责分三类,混用是多数问题的来源,如图 3-1 所示。

flowchart LR
    G["全局属性"] --> I["标识类<br/>id / class"]
    G --> S["状态类<br/>hidden / dir / lang"]
    G --> D["数据类<br/>data-* / title"]
    I --> I1["id 唯一,供锚点与关联"]
    I --> I2["class 供样式与脚本钩子"]
    S --> S1["hidden 隐藏但保留在树中"]
    D --> D1["data-* 供脚本读取,不参与样式"]

图 3-1 全局属性的三类职责

图上可见:id 与 class 都不承担语义,语义由标签本身决定;把内容含义写进 class 名里,朗读软件读不到。

3.2 三类原生交互元素

<!-- 运行环境:Chrome 130+;body 内内容 -->
<section>
  <h2>常见问题</h2>
  <details>
    <summary>为什么 id 不能重复?</summary>
    <p>id 用于锚点跳转与 label 关联,重复后浏览器只认第一个,关联全部失效。</p>
  </details>
  <details open>
    <summary>hidden 与不写元素有什么区别?</summary>
    <p>hidden 的元素仍在文档树中,可被脚本恢复;不写元素则不存在。</p>
  </details>
</section>

<p>
  上传进度:
  <progress value="42" max="100">42%</progress>
  磁盘占用:
  <meter value="0.72" min="0" max="1" low="0.5" high="0.85">72%</meter>
</p>

<button id="open">查看说明</button>

<dialog id="tip">
  <p>这是一段说明文字,按 Esc 可关闭。</p>
  <form method="dialog">
    <button>关闭</button>
  </form>
</dialog>

<script>
  const dialog = document.getElementById('tip');
  document.getElementById('open').addEventListener('click', () => dialog.showModal());
</script>

全局属性的使用边界见表 3-1。

属性 允许值 / 说明 常见误用
id 全文档唯一,字母开头 同一 id 用于多个元素
class 空格分隔的多个类名 用类名表达内容含义
hidden 布尔属性,隐藏但保留 用 hidden 代替条件不渲染
lang 语言码,如 zh-CN 只在 html 上写,混排外语不标注
dir ltr / rtl / auto 阿拉伯语等右排文字不标注
data-* 自定义数据,脚本读取 把大量业务数据塞进属性
tabindex 0 或 -1,正数会打乱顺序 使用 tabindex="3" 自定义顺序
title 补充说明,悬停显示 当作必读信息,移动端无法悬停
contenteditable 可编辑区域 需要富文本时未做输入校验

原生交互元素与脚本实现的对比见表 3-2。

需求 原生写法 脚本实现的代价
折叠面板 details + summary 需维护展开状态、键盘操作与朗读语义
弹层 dialog.showModal() 需自行处理焦点陷阱、Esc 与遮罩
进度 progress / meter 需额外绘制与无障碍标注

4 验证与讨论

  1. 保存文件,刷新页面,确认折叠面板默认收起、第二个面板默认展开。
  2. 只用键盘操作:Tab 聚焦到 summary,按 Enter 或空格展开;聚焦到按钮并打开弹层,按 Esc 关闭。
  3. 执行 document.querySelectorAll('#tip').length,预期为 1;把某处 id 改成重复值后再次执行,观察选择器仍只返回一个元素。
  4. 对照表 4-1 检查四项状态表现。
检查项 预期结果 说明
折叠键盘操作 Enter 可展开/收起 原生行为
弹层焦点 打开后焦点进入弹层,Esc 可关 showModal 行为
进度语义 朗读软件读出百分比 元素自带角色
id 唯一性 重复时选择器只命中第一个 违反唯一性后的表现

讨论与局限。 dialog 的 showModal 在旧浏览器不可用,需要回退方案;details 的动画无法只用 HTML 控制。另 data-* 只适合少量、与元素强相关的数据,列表类数据仍应走接口。

5 常见问题

现象 原因 处理
label 点击不聚焦输入框 关联的 id 重复,浏览器取第一个 保证 id 全文档唯一
折叠面板无法用键盘打开 用 div 加脚本模拟,未用 details 改用 details + summary
弹层打开后仍能操作背景 用了 show() 而非 showModal() 改 showModal()
键盘 Tab 顺序错乱 使用了正数 tabindex 改为 0 或 -1,靠文档顺序排列
外语段落朗读错误 未标注 lang 在对应元素上写 lang="en"

6 结论

序号 结论 依据
1 id 唯一、class 只作钩子,语义交给标签 图 3-1
2 hidden 隐藏但保留,删元素才是删除 表 3-1
3 折叠、弹层、进度优先用原生元素 表 3-2
4 tabindex 只用 0 与 -1 表 3-1

参考文献

[1] MDN Web Docs · 全局属性,https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes(访问于 2026-10-29)
[2] MDN Web Docs · dialog 元素,https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/dialog(访问于 2026-10-29)

返回文章列表

评论 0

0/2000

还没有评论,快来抢沙发吧~