:target伪类仅支持单入口单关闭的简单弹窗,无法实现多模态共存、Esc关闭、焦点管理、动态DOM加载、遮罩点击关闭等复杂交互,故不能替代JS驱动的弹窗组件。

不能用 CSS 工具库实现“无 JS 依赖的复杂弹窗组件”——工具库本身不解决复杂交互,而“复杂”和“无 JS”在当前浏览器生态下天然互斥。
:target 伪类能撑起多复杂的弹窗?
它只响应 URL hash 变化,适合单入口、单关闭、无状态切换的场景。比如点击 #login 链接打开登录框,再点内部 × 或遮罩关闭(靠跳转 # 清空 hash)。但以下情况它直接失效:
- 同一页面多个模态框需独立开关(
#modal1和#modal2无法共存控制) - 需要键盘
Esc关闭、Tab焦点管理、焦点捕获 - 内容动态加载后才渲染 DOM(
:target不监听 DOM 插入,只认初始存在的id) - 遮罩层点击不关闭弹窗(需阻止事件冒泡,这必须 JS)
anchor-name + anchor() 能替代 Popper.js 吗?
不能。它只做定位计算,且目前仅 Chrome/Edge 125+ 支持,Safari/Firefox 无计划支持。即便启用,也必须配合 JS 才能工作:
-
anchor-name: --trigger必须写在position: relative/absolute/fixed元素上,display: none的元素会丢失锚点 -
top: anchor(--trigger bottom)只能在top/inset等定位属性中使用,不能用于margin或动画缓动 - 没有溢出自动翻转(bottom → top)、滚动时重定位、视口边界检测——这些全得 JS 补
- 生产环境必须加
@supports (anchor-name: --test)检测,并 fallback 到 JS 计算
为什么 Bootstrap Modal、Headless UI 这些“CSS 组件”仍需 JS?
它们的 CSS 类(如 .modal、.open)只是样式契约,不带行为逻辑。真正驱动的是背后的 JS:
- Bootstrap 的
data-bs-toggle="modal"触发bootstrap.bundle.js中的事件监听器 - Headless UI 的
是 React 组件,内部用useEffect监听Esc、管理aria-modal属性、挂载/卸载 portal - 所谓“CSS-only”版本(如官方 demo 里的纯 class 示例)只展示样式,不触发任何显示逻辑
真正容易被忽略的点是:可访问性(a11y)不是锦上添花,而是模态框合法存在的前提。焦点锁、aria-hidden 切换、屏幕阅读器通告、键盘导航闭环——这些没 JS 就是残缺的。别为了“零 JS”牺牲基础可用性,该用 dialog 元素就用,该配 focus-trap 就配。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











