学完这篇你能拿到一份「HTML5 里被严重低估的标签清单」,并且每个标签都带可直接粘贴的示例代码、支持情况提醒和常见坑点,让你少写几百行 JS,少引几个第三方库。
第一步:用 <details> / <summary> 干掉 90% 的折叠 JS
这是被低估榜第一名。折叠面板、FAQ、答案展开,浏览器原生就支持:
<details open>
<summary>查看答案</summary>
<p>这里是折叠后才显示的内容。</p>
</details>
open 属性控制默认展开。2026 年更值得用的是同名互斥手风琴:
<details name="faq"><summary>问题一</summary><p>答案一</p></details>
<details name="faq"><summary>问题二</summary><p>答案二</p></details>
name 相同的 <details> 同组内只能展开一个,展开时会自动收起上一个——不用写一行 JS。样式上可以配合 details[open] summary 做箭头翻转,::marker 或 list-style: none 去掉默认三角。
注意:<summary> 必须是 <details> 的第一个子元素,否则浏览器不会把它当标题栏渲染,点击区域会失效。
第二步:用 <dialog> 替掉弹窗组件库
原生模态框的完整能力,包括遮罩层、焦点陷阱、Esc 关闭、::backdrop 伪元素:
<dialog id="dlg">
<form method="dialog">
<p>确定要删除这条记录吗?</p>
<button value="cancel">取消</button>
<button value="ok">确定</button>
</form>
</dialog>
<script>
const dlg = document.getElementById('dlg');
dlg.showModal();
dlg.addEventListener('close', () => {
console.log(dlg.returnValue); // "ok" 或 "cancel"
});
</script>
<form method="dialog"> 里按钮的 value 会自动写进 returnValue,连回调解包都省了。
注意:必须用 showModal() 才有遮罩和焦点管理;直接加 open 属性只是个非模态的可见框,页面其他部分仍可点击,很容易误判成"弹窗库不好用"。
第三步:表单里的四个「隐形工具」
<datalist> 给输入框挂候选,用户仍可自由输入:
<input list="cities" name="city">
<datalist id="cities">
<option value="北京">
<option value="上海">
<option value="广州">
</datalist>
<output> 专门放计算结果,天然带 for 关联、可被无障碍工具朗读:
<form oninput="r.value = Number(a.value) + Number(b.value)">
<input type="number" id="a" value="1">
<input type="number" id="b" value="2">
<output name="r" for="a b">3</output>
</form>
<meter> 表示"已知范围内的量"(评分、水位、磁盘占用),<progress> 表示"任务完成度":
<meter min="0" max="100" low="30" high="70" optimum="90" value="82">82%</meter>
<progress max="100" value="40">40%</progress>
<progress></progress> <!-- 不写 value 就是不确定进度动画 -->
注意:<datalist> 在部分移动端浏览器里是弱化渲染(有的直接不弹候选),别把它当强校验用;真要保证选项,还是配 <select> 或自己做校验。
第四步:语义标签,让机器读懂你的页面
这些标签不改变外观,但对 SEO 和读屏软件很重要:
<p>更新于 <time datetime="2026-03-01">3 月 1 日</time></p>
<p>用户 <bdi>@李雷</bdi> 关注了你</p>
<p>拼音:<ruby>中<rp>(</rp><rt>zhōng</rt><rp>)</rp></ruby></p>
<p>关键是 <mark>事件循环</mark>。</p>
<time datetime> 给日期一个机器可读格式;
<bdi> 隔离方向不确定的文本(中东语用户名混排时不会把整行方向带歪);
<ruby> / <rt> / <rp> 做注音,<rp> 是给不支持 ruby 的老浏览器兜底的括号;
<wbr> 标记长 URL 的软换行点;
<search> 包裹站内搜索表单,语义比 <form role="search"> 更直接。
第五步:两个新全局属性 popover 和 inert
<button popovertarget="menu">打开菜单</button>
<div id="menu" popover>菜单内容</div>
<div id="page" inert>页面主体</div>
popover 自带顶层渲染、点击外部关闭(light dismiss)、Esc 关闭;改成 popover="manual" 就是只能手动关的版本。inert 让整块区域不可点击、不可聚焦、对辅助技术隐藏,做抽屉或弹窗背景冻结极其省事。
注意:inert 是"全有全无"的,别顺手加在表单容器上忘了移除,否则用户提交按钮会彻底点不动,排查时很难想到。
第六步:性能相关属性别浪费
<img src="hero.avif" alt=""
width="1200" height="600"
decoding="async" fetchpriority="high">
<img src="thumb.avif" alt=""
width="400" height="300" loading="lazy" decoding="async">
首屏大图给 fetchpriority="high",屏幕外图片给 loading="lazy",同时一定写上 width / height 防布局抖动。
注意:首屏 LCP 图千万别加 loading="lazy",会让加载时机被推迟,实测首屏指标会明显变差。
第七步:上线前做一次能力检测
不要靠 UA 判断,直接用特性检测兜底:
if ('showModal' in HTMLDialogElement.prototype) {
dlg.showModal();
} else {
dlg.setAttribute('open', ''); // 降级为普通显示
}
if ('popover' in HTMLElement.prototype) { /* 原生 popover */ }
写完顺手去 MDN 或 caniuse 查一眼 Baseline 状态,确认你的目标浏览器版本线。
小结
<details name>、<dialog showModal()>、popover、inert 这四个是替代 JS 组件库性价比最高的;
<datalist> / <output> / <meter> / <progress> 属于"表单四件套",能用就比手搓 div 强;
<time> / <bdi> / <ruby> / <wbr> / <search> 不改视觉但提升可访问性与机器可读性;
- 首屏图给
fetchpriority="high",非首屏图才用 loading="lazy",并始终写宽高;
- 所有新特性都做特性检测降级,别只靠 UA 判断。