:target伪类在url fragment与元素id匹配时生效,可纯css触发灯箱;需将遮罩层置于target元素之后并用~选择器联动,关闭靠href="#"重置hash,但存在浏览器兼容、键盘支持等局限。

什么是 :target 伪类,它为什么能触发灯箱?
:target 只在 URL 的 fragment(即 # 后面的部分)与页面中某个元素的 id 匹配时生效。比如访问 page.html#photo1,且页面里有 <div id="photo1">,那这个 <code><div> 就是 <code>:target。
它不依赖 JS,天然具备“显示/隐藏切换”的触发能力——只要改 URL 的 hash,样式就能响应。但注意:它只对当前匹配的单个元素生效,不能直接控制兄弟或父容器;所以灯箱结构必须让遮罩层和内容区能被 :target 间接影响。
灯箱 HTML 结构怎么组织才有效?
关键不是把图片塞进 :target 元素里,而是让 :target 本身成为“触发锚点”,再用 CSS 选择器联动遮罩和内容。常见可靠结构:
- 遮罩层(
<div class="lightbox-overlay">)放在所有灯箱内容之前,且不设 <code>id - 每个灯箱内容块带唯一
id(如id="img-abc"),并紧邻其后的遮罩层(或通过~选择器定位) - 触发链接指向该
id:@#@#@#@#@#@#@#@#@#@0
这样当点击链接,img-abc 成为 :target,你就可以写:
img-abc:target ~ .lightbox-overlay {
opacity: 1;
pointer-events: auto;
}
要点:
- 遮罩层必须在
:target元素之后(才能用~或+) -
.lightbox-overlay初始需设opacity: 0; pointer-events: none;,否则会挡住下面的链接 - 不要用
:target直接控制display: none/block,因为 transition 不支持display动画
如何关闭灯箱?用户点哪都能退?
关闭本质是让 URL hash 变成一个不匹配任何 id 的值,比如 # 或 #close(只要没对应元素)。最稳妥做法:
- 在遮罩层里放一个空链接:
@#@#@#@#@#@#@#@#@#@1 - 或在灯箱内容内部加关闭按钮:
@#@#@#@#@#@#@#@#@#@2 - 确保页面顶部没有
id=""或id="close"这类干扰元素
注意:
-
href="#"会让浏览器滚动到页面顶部,可用href="javascript:void(0)"避免,但会失去纯 CSS 能力;更推荐接受轻微滚动,或用scroll-behavior: smooth缓和体验 - 不要给关闭按钮设
id,否则它自己变成:target,可能意外触发其他样式
移动端和键盘导航下容易出什么问题?
:target 灯箱在 Safari iOS 和部分安卓浏览器中,hash 变化后可能不立即重绘,导致遮罩延迟出现;另外,按 Esc 键无法关闭(没 JS 就没事件监听)。
解决方案有限但实用:
- 给遮罩层加
will-change: opacity提升渲染优先级 - 所有可聚焦元素(如关闭按钮)加上
tabindex="0",保证键盘能到达 - 关闭按钮用
<button type="button" onclick="location.hash=''"></button>是 JS 回退方案,但已违背“纯 CSS”前提——这时候得承认:纯 CSS 灯箱天生不支持 Esc 关闭,也不保证所有浏览器 100% 即时响应
真正的难点不在写法,而在于接受它的边界:它是 URL 驱动的状态映射,不是交互组件。一旦需要键盘支持、历史记录管理、或关闭动画同步,就得引入 JS。











