:target 通过匹配 URL 中的 fragment identifier(如 #img1)控制灯箱显示,点击链接会自动滚动并更新地址栏,这是规范行为;需确保 id 与 href 完全一致(大小写、符号敏感),配合 visibility/opacity 实现平滑过渡,并用 JS 补足 Esc 和点击遮罩关闭逻辑。

为什么 :target 能控制灯箱显示,但点击后 URL 变了
因为 :target 本质是匹配当前 URL 中 # 后的 fragment identifier —— 点击带 href="#img1" 的链接,浏览器自动滚动并让 #img1 元素成为 :target,同时修改地址栏。这不是 bug,是规范行为。
实操建议:
- 给每张图片配唯一
id(如id="img1"),对应链接的href="#img1" - 灯箱遮罩层(
<div class="lightbox">)本身不需 <code>id,但它的子元素(如<img alt="CSS如何利用:target实现灯箱图片放大效果_通过锚点跳转控制全屏遮罩" >)要和:target关联,常用写法:.lightbox:target { display: flex; } - 若遮罩层独立于图片 DOM 结构,不能直接用
:target控制它——得把id放在遮罩层自己身上 - 初始设
visibility: hidden; opacity: 0; pointer-events: none; -
:target触发时只改visibility: visible; opacity: 1; pointer-events: auto; - 配合
transition: opacity 0.2s ease实现淡入,避免突兀 - 不用
display就不会触发回流,动画更顺,也方便加transform: scale()做缩放入场 - 给遮罩层加
tabindex="-1",确保能被 JSfocus(),便于后续捕获Esc - 监听
document.addEventListener('keydown', e => e.key === 'Escape' && history.back()) - 监听遮罩层点击:当
e.target === e.currentTarget(即点在遮罩背景上,非图片本身),执行history.back() - 不要用
window.location.hash = '',它会跳到页面顶部;history.back()或history.pushState()更精准 - 确保
<meta name="viewport" content="width=device-width, initial-scale=1">存在 - 避免对
html或body设scroll-behavior: smooth,它会干扰:target的锚点定位 - 如果图片在折叠区域(如
position: sticky容器内),:target可能不滚动到可视区——此时需 JS 强制element.scrollIntoView({ block: 'center' }) - Android Chrome 一般没问题,但旧版 UC、QQ 浏览器可能完全不支持
:target,得降级为 class 切换
:target 配合 display 和 visibility 的区别在哪
很多人用 display: none 初始隐藏灯箱,再用 :target { display: flex; } 显示,结果发现页面闪动或布局重排明显。这是因为 display 切换会彻底移除/重建渲染流。
更稳的做法是:
立即学习“前端免费学习笔记(深入)”;
点击灯箱外部或按 Esc 关不掉?关键在事件绑定和 focus 管理
:target 是纯 CSS 机制,它无法监听点击或键盘事件,所以“点遮罩外关闭”“按 Esc 关闭”必须靠 JS 补足。
常见错误现象::target 显示了灯箱,但用户只能靠浏览器后退或手动删地址栏 #xxx 才能关。
实操建议:
移动端 Safari 下 :target 不触发?检查 viewport 和 scroll-behavior
iOS Safari 对 fragment 滚动和 :target 渲染有延迟,尤其在 <meta name="viewport"> 缺失或 scroll-behavior: smooth 开启时容易失效。
兼容性要点:
真正麻烦的是 fragment identifier 和实际 DOM id 的大小写、特殊字符一致性,比如 id="user-photo-1" 和 href="#user_photo_1" 看似一样,其实不匹配——:target 匹配严格区分符号与大小写。


















