跳到主要内容

用 HTML 替代 JavaScript

· 阅读需 5 分钟
阿飞
阿飞

JavaScript 曾经是 Web 交互的默认解法,但今天很多常见场景已经可以靠原生 HTML 和 CSS 直接实现。

这不是"反 JS",而是把浏览器本身就能做的事情还给浏览器,让 JavaScript 专注于真正需要它的场景。

本文覆盖四种高频交互模式——手风琴折叠、自动筛选下拉、模态弹出层、屏幕外导航,展示如何用更少的代码和依赖实现更稳的体验。

手风琴 / 可展开内容面板

<details><summary> 提供了纯 HTML 的折叠面板方案,无需任何 JS。

适用场景: FAQ 列表、产品说明、可折叠的详细信息

基本实现:

实时编辑器
<details>
  <summary>点击展开</summary>
  <p>内容默认隐藏,点击 summary 后显示。</p>
</details>
结果
Loading...

添加 open 属性可设置默认展开:

实时编辑器
<details open>
  <summary>点击收起</summary>
  <p>内容默认可见,点击 summary 后隐藏。</p>
</details>
结果
Loading...

给同组的 <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>
结果
Loading...

提示: 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>
结果
Loading...

<datalist> 也支持 numbertime 等输入类型:

实时编辑器
<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>
结果
Loading...

注意: Firefox 目前仅支持基于文本的输入类型,datetimerangecolor 暂不兼容。移动端的样式和可访问性也存在差异,建议实际测试后再上线。


模态框 / 弹出层

popoverpopovertarget 属性可以替代 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>
结果
Loading...

注意: 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 来做。

ICP备案/许可证号:蜀ICP备2025139266号-1
beian 川公网安备51013202000132号