transition必须写在默认状态里,不能只靠:target或class切换;弹窗需用position: fixed、visibility: hidden配合step-end过渡;遮罩层要fixed且z-index足够高;ios safari需避免transform、启用will-change和translatez(0)优化渲染。

transition必须写在默认状态里,不能只靠:target或class切换
很多人给弹窗加:target { opacity: 1; }却没动画,是因为transition没声明在初始规则中。浏览器只在属性值“变化时”触发过渡,而:target只是匹配状态,不产生变化——除非起始态和目标态的opacity不同。
正确做法是把transition: opacity 0.3s ease, visibility 0.3s step-end;写在弹窗容器的常态选择器里,比如#modal或.dialog,而不是#modal:target里。
- 起始态必须设
opacity: 0; visibility: hidden; -
:target态只负责改回opacity: 1; visibility: visible; - 别用
display: none替代visibility: hidden,它无法过渡 -
visibility配step-end是为了防止淡出末尾闪一下
position: fixed不是可选项,是必要项
弹窗不设position: fixed或absolute,它仍参与文档流。一旦:target匹配,页面内容会被往下顶,出现明显抖动——这不是动画卡顿,是布局重排。
移动端 Safari 在哈希跳转后若页面已滚动,:target样式有时延迟重绘;fixed能绕过部分重排问题。遮罩层也必须fixed,否则滚动后就盖不住内容。
-
z-index要显式设高值(如z-index: 1000),别依赖默认堆叠上下文 - 遮罩层建议用
background: rgba(0,0,0,0.6)而非纯黑,更柔和 - 避免在
:target规则里写transform: scale(),iOS Safari 支持不稳定
点击遮罩关闭弹窗,纯CSS能做但有硬约束
想点遮罩关弹窗,不能只写a.close:target { display: none; }——因为#不匹配任何id,:target永远不生效。
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
必须让哈希变更真实触发一次:target匹配:遮罩链接指向一个空元素,比如@#@#@#@#@#@#@#@#@#@0,再加一个<div id="close"></div>(可藏在页脚)。
- 这样点遮罩时 URL 变成
#close,触发#close:target,使弹窗容器失配:target,自动退回默认隐藏态 - iOS Safari ≤15.4 连点遮罩可能丢哈希变更,加
pointer-events: none到遮罩上反而更稳 - 遮罩本身不要设
transition,只让它控制弹窗的:target状态
移动端 Safari 卡顿/闪一下,关键在渲染提示和属性组合
这不是代码错,是 iOS Safari 的合成层调度机制差异。它对哈希驱动的opacity过渡支持尚可,但若叠加transform或嵌套在滚动容器里,容易掉帧。
最稳方案是放弃transform位移,改用top/left + opacity组合,并提前告诉浏览器这个元素会变:
transition: opacity 0.25s ease, top 0.25s ease;- 弹窗容器加
will-change: opacity;(仅需在要动画前加,别全局滥用) - 避免对
body或全屏遮罩直接设opacity过渡,可加transform: translateZ(0)强制GPU加速 - 测试时打开 Safari 开发者工具 → Rendering → 勾选 Paint Flashing,看是否整块重绘
真正麻烦的不是怎么写过渡,而是怎么让:target状态切换和transition时机咬合——稍有错位,动画就消失或卡半截。尤其在快速连点、滚动中触发时,得靠fixed定位、step-end、will-change三者配合压住渲染节奏。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










