用 HTML 替代 JavaScript
JavaScript 曾经是 Web 交互的默认解法,但今天很多常见场景已经可以靠原生 HTML 和 CSS 直接实现。
这不是"反 JS",而是把浏览器本身就能做的事情还给浏览器,让 JavaScript 专注于真正需要它的场景。
本文覆盖四种高频交互模式——手风琴折叠、自动筛选下拉、模态弹出层、屏幕外导航,展示如何用更少的代码和依赖实现更稳的体验。
手风琴 / 可展开内容面板
<details> 和 <summary> 提供了纯 HTML 的折叠面板方案,无需任何 JS。
适用场景: FAQ 列表、产品说明、可折叠的详细信息
基本实现:
<details> <summary>点击展开</summary> <p>内容默认隐藏,点击 summary 后显示。</p> </details>
添加 open 属性可设置默认展开:
<details open> <summary>点击收起</summary> <p>内容默认可见,点击 summary 后隐藏。</p> </details>
给同组的 <details> 设置相同的 name 属性,即可实现排他展开——一次只打开一个面板:
<pre> <details name="faq" open> <summary>第一个问题</summary> <p>默认展开,打开其他面板时自动关闭。</p> </details> <details name="faq"> <summary>第二个问题</summary> <p>点击后打开,同时关闭同组其他面板。</p> </details> <details name="faq"> <summary>第三个问题</summary> <p>同上,互斥展开。</p> </details> </pre>
提示:
name属性实现排他展开是较新的特性,浏览器支持有限,使用前请确认目标用户的浏览器兼容性。
带自动筛选的输入框
<input> 搭配 <datalist> 即可创建输入时自动筛选选项的下拉框,无需引入任何自动补全库。
适用场景: 搜索框、产品筛选、表单快速填写
基本实现:
<pre> <label for="browser">浏览器</label> <input type="text" list="browsers" id="browser" name="browser" size="50" autocomplete="off" /> <datalist id="browsers"> <option value="Arc"></option> <option value="Brave"></option> <option value="Chrome"></option> <option value="DuckDuckGo"></option> <option value="Firefox"></option> <option value="Microsoft Edge"></option> <option value="Opera"></option> <option value="Safari"></option> <option value="Tor"></option> <option value="Vivaldi"></option> </datalist> </pre>
<datalist> 也支持 number、time 等输入类型:
<pre> <label for="quantity">数量</label> <input type="number" list="quantity-options" id="quantity" name="quantity" /> <datalist id="quantity-options"> <option value="1"></option> <option value="2"></option> <option value="5"></option> <option value="10"></option> <option value="20"></option> <option value="50"></option> </datalist> <label for="appointment">预约</label> <input type="time" list="appointments" id="appointment" name="appointment" /> <datalist id="appointments"> <option value="12:00"></option> <option value="13:00"></option> <option value="14:00"></option> </datalist> </pre>
注意: Firefox 目前仅支持基于文本的输入类型,
date、time、range、color暂不兼容。移动端的样式和可访问性也存在差异,建议实际测试后再上线。
模态框 / 弹出层
popover 和 popovertarget 属性可以替代 JS 驱动的模态框、弹出层和覆盖层。
适用场景: 提示信息、确认对话框、临时操作面板
自动弹出层(默认行为)
支持"轻量关闭"(点击外部或按 Esc 关闭)。打开一个自动弹出层会自动关闭其他已打开的自动弹出层。
<button popovertarget="pop-auto">切换弹出层</button>
<dialog popover id="pop-auto">我是"自动"弹出层</dialog>
提示弹出层(hint)
同样支持轻量关闭,但打开时不会关闭其他提示弹出层,适合同时展示多条提示。
<pre> <button popovertarget="pop-hint">切换弹出层</button> <dialog popover="hint" id="pop-hint">我是"提示"弹出层</dialog> </pre>
注意: Firefox 和所有 iOS 版本尚不支持提示弹出层,兼容性详情。
手动弹出层(manual)
不支持轻量关闭,必须通过按钮或 JS 显式关闭,适用于需要用户主动操作后才能关闭的场景(如确认对话框)。
<button popovertarget="pop-manual">切换弹出层</button>
<dialog popover="manual" id="pop-manual">我是"手动"弹出层</dialog>
屏幕外导航
结合 popover 和 CSS,可以实现无需 JS 的侧滑导航菜单。
适用场景: 移动端汉堡菜单、侧边抽屉导航
<button popovertarget="menu">打开菜单</button>
<nav popover id="menu">
<ul>
<li><a href="/">首页</a></li>
<li><a href="/about">关于</a></li>
<li><a href="/contact">联系</a></li>
</ul>
</nav>
#menu {
margin: 0;
height: 100vh;
translate: -100vw;
transition: translate 0.3s ease;
}
#menu:popover-open {
translate: 0;
}
- 使用
<nav>赋予语义,也可以替换为<div>、<aside>等元素 - 弹出层默认
position: fixed,关闭时被推到屏幕外,打开时回到可视区域 - 如需覆盖浏览器默认的居中样式,记得设置
margin: 0 - 可通过
::backdrop伪元素添加遮罩
#menu::backdrop {
background: rgb(0 0 0 / 50%);
}
写在最后
浏览器原生能力比我们想象中强大得多。优先使用语义 HTML 和标准特性,不只是减少代码量——更少的 JS 意味着更快的加载、更少的运行时错误、更好的可访问性,以及更低的长线维护成本。
下次写交互前,先问一句:这件事真的需要 JS 吗? 如果答案是不需要,那就让 HTML 来做。