position: fixed + transform: translatey() + @keyframes 是最稳组合,因 top 动态修改触发重排致 ios safari 卡顿、错位;transform 走 gpu 加速,动画须纯 css 定义、用 forwards 保持终态,多通知需按 dom 顺序动态计算偏移,隐藏宜用 visibility: hidden 而非 remove() 或 display: none。

用 position: fixed + transform: translateY() + @keyframes 是最稳的组合,别碰 top 动态改值——iOS Safari 卡顿、滚动错位、动画重置全是它惹的祸。
为什么不能用 JavaScript 改 top 实现滑入
常见错误是写 element.style.top = '-60px' → setTimeout 逐步设为 '16px'。这会强制浏览器频繁重排,尤其在 iOS Safari 上:快速滚动后通知条位置偏移、返回页面时卡在半空、动画掉帧明显。
根本问题在于:top 触发 layout,而 transform 走 GPU 加速通道。现代浏览器对 CSS 动画(尤其是 transform 和 opacity)有深度优化,JS 驱动的数值插值完全绕过了这套机制。
- 动画结束状态必须纯靠 CSS 定义,不能混用
top和transform - 若初始用
top: -60px,后续又加transform: translateY(0),浏览器可能忽略后者或产生冲突位移 - 禁用
will-change: transform在长列表页能提前触发硬件加速,但别滥用——只加在通知元素上,不加在父容器
@keyframes 滑入动画怎么写才不“闪一下”
关键不是“从哪来”,而是“起始状态是否真在屏幕外”。很多代码写 from { transform: translateY(0); },结果动画根本不可见——因为元素一渲染就在视口里了。
正确写法必须保证初始位移超出视口顶部:
@keyframes slideInTop {
from {
transform: translateY(-100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.notification {
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
animation: slideInTop 0.3s ease-out forwards;
}
-
forwards必须加,否则动画一结束就回退到初始transform状态(比如被 JS 或其他 CSS 覆盖) - 别用
transition替代@keyframes:transition 只响应属性变化,而“首次显示”没有前一个状态可过渡 - 如果通知条高度不固定(比如文字长度不定),
translateY(-100%)比translateY(-60px)更安全——它始终是自身高度的 100%
多个通知堆叠时,如何避免互相遮挡或错位
当连续调用 showNotification(),新通知不能简单覆盖旧的,也不能全堆在 top: 16px。得按 DOM 顺序计算垂直偏移。
核心逻辑:新通知的 top = 所有已存在通知的高度之和 + 间距(如 12px)。但注意——这个“所有已存在”必须是当前已渲染且未关闭的节点,且顺序必须与 DOM 中一致。
- DOM 节点必须追加到
document.body末尾,不能插在某个容器里;否则querySelectorAll('.notification:not(.hidden)')会漏掉或顺序错乱 - 别每次重算全部通知高度,只取前一个兄弟节点的
offsetHeight+ 间距即可(前提是 DOM 插入顺序即显示顺序) - 用
getComputedStyle(el).height不可靠——它返回的是 computed 值,可能含auto或受display: none影响;优先用el.offsetHeight - 关闭通知时,先触发动画,等
animationend事件后再从 DOM 移除,否则高度计算会出错
隐藏后要不要从 DOM 删除
不建议立即 remove()。动画结束后保留节点但设 visibility: hidden + opacity: 0 + transform: translateY(-20px),比删了再重建更轻量。
原因很实际:重建 DOM 节点要走完整生命周期(解析、样式计算、布局、绘制),而复用已有节点只需更新合成层属性。尤其在高频弹出场景(如表单批量校验),性能差距明显。
- 必须避免
display: none:它会触发重排,下次显示时动画可能“闪一下”才开始 - 如果通知条内含视频、iframe 或第三方脚本,隐藏时需手动暂停(比如
video.pause()),否则后台仍在运行 - 用
visibility: hidden时,确保父容器没设overflow: hidden,否则可能裁剪掉动画过程中的位移
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











