transition必须写在默认状态,移动端无持续hover故需基础样式声明;touch-action: manipulation解决触控反馈缺失;优先用transform/opacity避免重排;scroll中改样式应改class而非直接操作style。

transition 必须写在默认状态,不能只靠 :hover 或 :active
移动端没有持续 hover 状态,首次点击才触发 :hover,且部分 WebView 会忽略它。把 transition 写在 :hover 里,结果就是:点一下有动画,松手就“啪”地跳回,毫无过渡可言。
必须把 transition 声明放在基础样式中,比如 .btn 或 button 元素本身:
.btn { transition: transform 0.2s ease, opacity 0.25s ease; }.btn:active { transform: scale(0.98); opacity: 0.85; }
这样点击(:active)和释放(回退到默认态)两个方向都受控。别偷懒用 transition: all,它会让 outline、box-shadow 等非预期属性也参与动画,造成干扰。
必须加 touch-action: manipulation
iOS Safari 和很多安卓 WebView 默认压制按钮的原生点击反馈,哪怕 CSS 写得完全正确,用户也会感觉“点不动”或动画卡在中间。这不是代码问题,是浏览器行为。
立即学习“前端免费学习笔记(深入)”;
解决方法非常直接:
- 给所有需要过渡响应的交互元素加
touch-action: manipulation; - 尤其对
button、a、带onclick的div不可省略 - 不加这句,
:active动画可能只执行一半,甚至完全不触发
注意:它不影响桌面端,也不影响键盘焦点,纯为触控优化。
优先用 transform 和 opacity,避开 layout 属性
在低端设备或复杂页面中,width、height、margin、left 这类属性会触发重排(reflow),导致卡顿甚至丢帧。而 transform 和 opacity 能稳定触发 GPU 加速。
常见替换方案:
- 想“放大按钮”?用
transform: scale(1.05),不是width: 120% - 想“上浮效果”?用
transform: translateY(-2px),不是margin-top: -2px - 想“淡出”?用
opacity: 0+visibility: hidden(后者需 JS 在动画结束后设置,否则不可过渡)
如果真要用 max-height 做下拉菜单过渡,务必设具体值(如 max-height: 240px),不能留 auto——它不可插值,动画会失效。
避免 scroll 事件中直接改样式,用 class 切换
滚动时动态调节透明度或背景色,很多人在 scroll 回调里直接写 element.style.opacity = ...,结果严重掉帧。因为每次写入都会强制同步计算布局。
正确做法是预设 class,JS 只负责切换:
- 定义
.nav-scrolled { background-color: rgba(255,255,255,0.95); } - 监听
scroll,用classList.toggle('nav-scrolled', window.scrollY > 50) - CSS 中确保
transition: background-color 0.4s ease写在基础类(如.nav)上
额外提醒:iOS Safari 上,给这类元素加 will-change: transform 和 backface-visibility: hidden 可防闪烁,但仅在必要时加——滥用会增加内存开销。
最容易被忽略的一点是:过渡是否生效,不取决于你写了多少行 CSS,而取决于「那个属性是否真的发生了可插值的变化」。比如 display: none → block、background-image 改 URL、或者 opacity 从没在默认态声明过初始值——这些都会让动画静默失败。



















