平滑隐藏元素需opacity与visibility协同:opacity控制渐变可见性,visibility控制语义和交互;淡出时先opacity动画再transitionend设visibility:hidden和pointer-events:none,淡入则反之;须同步aria-hidden、pointer-events和视觉状态以保障无障碍。

想让元素隐藏得既平滑又干净,光靠 opacity 或 visibility 单独用都不够。opacity 负责“看得见看不见”,visibility 管“能不能点、读不读得到”。两者配合,才能兼顾动画、交互和无障碍。
opacity 做渐变,visibility 控语义
opacity 从 1 到 0 可以自然过渡,但值为 0 时元素还在页面里——能被 Tab 键聚焦、被屏幕阅读器读出、甚至可能挡住下面的按钮。这时候 visibility: hidden 就派上用场:它让元素退出可访问树,也不响应鼠标事件。但 visibility 本身不能过渡,所以必须由 opacity 动画“带节奏”。
- 淡出时:先设 opacity: 0(加 transition),等动画结束再切 visibility: hidden
- 淡入时:先设 visibility: visible(JS 提前写好),再加类触发 opacity: 1 动画
- 别在动画里直接写 visibility: hidden —— 浏览器会跳过绘制,动画直接失效
用 transitionend 精准卡点切换
CSS 自己没法判断“opacity 动画结束了没”,得靠 JavaScript 监听 transitionend 事件,只在 opacity 动画完成时才更新 visibility 和 pointer-events。
- 监听 event.propertyName === 'opacity',避免其他属性干扰
- 淡出后设 element.style.visibility = 'hidden' 和 element.style.pointer-events = 'none'
- 淡入前先还原 visibility 和 pointer-events,再加动画类
- 如果用了 animation-fill-mode: forwards,也要配 animationend 做清理
别漏掉无障碍和交互细节
用户看不见 ≠ 元素不存在。opacity: 0 的按钮仍可能被键盘聚焦,screen reader 也可能念出来。真正安全的隐藏,要三层同步:
立即学习“前端免费学习笔记(深入)”;
- 视觉层:opacity: 0
- 交互层:pointer-events: none(动画开始前就得加上)
- 语义层:aria-hidden="true"(或动画结束后移除 DOM)
- 表单控件优先用 visibility: hidden,它天然阻止 focus,比 opacity: 0 更稳妥
常见错误避坑清单
这些小疏忽会让效果打折扣,甚至引发误触或可访问性问题:
- 给 visibility 加 transition —— 完全无效,浏览器不插值
- 一触发隐藏就立刻 visibility: hidden —— opacity 动画根本来不及播
- 只靠 opacity: 0 隐藏敏感内容 —— DOM 还在,审查元素就能看到
- 用 display: none 初始化状态 —— 后续所有 CSS 动画都会中断
- 忘记 pointer-events: none —— 透明按钮依然能点,用户一脸懵


















