CSS 的 display: none、visibility: hidden 和 opacity: 0 有什么区别?
下面是一段教学用的模拟面试。
🧑💻 面试官:这三种方式都能让元素看不见,区别是什么?
🙋♂️ 我:display: none 不占位置,另外两个占位置。
🧑💻 面试官:弹窗已经 opacity: 0,用户却点不到后面的按钮,是为什么?
🙋♂️ 我:弹窗透明了,但可能仍然参与点击命中。
🧑💻 面试官:那加 pointer-events: none 就完全隐藏了吗?键盘 Tab 和屏幕阅读器又会怎么处理?
隐藏不能只看屏幕。还要检查它有没有占位、能不能交互,以及是否仍被辅助技术读到。
面试速答(60 秒版)
display: none 让元素及其子树不生成相应布局盒,通常不占页面位置,也不能作为普通可见控件接收焦点或点击。
visibility: hidden 保留布局位置,但不绘制元素,它本身不能接收焦点;子元素显式设置 visibility: visible 时,可能重新显示。
opacity: 0 只是让整个元素的绘制结果透明,布局位置还在,点击、键盘焦点和无障碍暴露也可能保留。所以,做淡出动画和做真正的隐藏不是同一个需求;交互元素需要同时管理命中、焦点与辅助技术状态,而不是只改透明度。

知识点详解:看不见的弹窗,为什么还挡着页面?
先用三张卡片看“位置还在不在”
假设页面从左到右放三张卡片,现在要隐藏中间那张。
设置 display: none 后,中间卡片不再生成布局盒。在普通流布局里,后面的卡片会利用空出来的位置。注意,DOM 节点并没有因此从文档中删除,脚本仍可能找到它。
visibility: hidden 则让中间卡片看不见,但位置保留,后面的卡片不会因为它隐藏就自动填过来。visibility 文档说明了占位和焦点行为。
opacity: 0 也保留位置,只是绘制结果完全透明。从布局这一项看,它和 hidden 有相似现象;但这不代表其他行为一样。
这里讨论普通元素的常见用法,不把 visibility: collapse 等特殊值混进这三个基本选项。
透明,为什么还能挡点击?
假设一个弹窗覆盖在按钮上方,关闭时只把 opacity 设成 0。
用户看见后面的按钮,但浏览器做点击命中测试时,透明弹窗仍可能是前面的目标。于是点击被它接住,后面的按钮收不到。这不是按钮坏了,而是不可见的覆盖层还在交互路径上。
opacity 文档明确提醒,透明元素仍可能响应指针事件和获取焦点。
可以按需要调整 pointer-events,让指针不再命中这个覆盖层。但 pointer-events 主要管理指针命中,不是统一关闭全部交互的开关。
例如按钮仍在键盘 Tab 顺序里,就可能在看不见的位置获得焦点;脚本也可能主动调用 focus。因此,还要根据控件类型与组件状态安排焦点、disabled、inert 等行为,不能只背一条 CSS。

谁能被屏幕阅读器读到?
display: none 和 visibility: hidden 的普通隐藏子树,通常也会从无障碍树移除。opacity: 0 则不自动表达“这个控件现在不可用”,辅助技术仍可能读到它。display 文档说明了相关无障碍影响。
所以,一个视觉上消失的弹窗,不能仍让键盘和屏幕阅读器在里面操作。关闭时,应把焦点交回合理位置,再按组件需要处理隐藏与交互状态。
aria-hidden 也不是随手补上的万能方案:它不会自动阻止焦点和点击,不应让仍可聚焦的内容一边接收焦点,一边被标成对辅助技术隐藏。
CSS 隐藏也不是权限控制。数据只要已经发到浏览器、留在 DOM 或脚本状态里,就不能因为看不见而被视为保密。
子元素能不能自己显示回来?
visibility 是会继承的属性,但后代可以明确设为 visible。因此,父元素 hidden 不一定意味着所有后代都永远不可见,需要看子元素有没有覆盖相应值。
display: none 不同:父元素不生成布局盒时,子树不能靠子元素改成 display: block 就跳出来正常显示。
opacity 又是另一种关系。父元素的透明度作用于整个绘制组,子元素即使 opacity: 1,也不能把这个整体结果中的自己重新变成不透明。
这三个行为,能帮助咱们判断“父亲隐藏了,孩子为什么还出现”或“孩子写了 opacity: 1 为什么仍看不见”。不能只记占位表。

做动画时,如何安排最后的隐藏?
假设弹窗需要先淡出,再真正退出交互。
可以把淡出阶段和最终隐藏阶段分开:动画时调整 opacity,关闭过程中按需要禁用交互;动画结束后,再移除元素或设置真正的隐藏状态。重新打开时,也要恢复对应状态与焦点。
如果依赖 transitionend,还应考虑动画被取消、减少动态效果设置或组件提前卸载。状态最终是否正确,不能只靠某个动画事件“应该会回来”。
具体动画方案按目标浏览器和组件框架判断,本题不承诺 display 永远不能参与过渡;现代 CSS 已有离散过渡等能力,不能把旧经验写成永久限制。
怎么验证没有留下“隐形按钮”?
分别隐藏同一个按钮,检查相邻元素位置、鼠标点击、Tab 焦点和无障碍树,再检查 DOM 是否仍存在。
不要只看截图。截图能证明这一次绘制看不见,不能证明用户再也操作不到它。弹窗还应测试关闭后,焦点有没有回到触发按钮附近。
面试官继续追问
display: none 会删除 DOM 和事件监听吗?
不会因为这个 CSS 声明自动删除节点或解除全部监听。是否销毁组件、停止计时器,是另外的生命周期问题。
opacity: 0 加 pointer-events: none,就能安全隐藏密码吗?
不能。它只是视觉和交互处理,数据如果已经到客户端,仍可能被查看。权限与敏感数据控制应在可信边界执行。
隐藏元素一定不占任何资源吗?
不一定。DOM、JavaScript 状态、计时器或订阅可能仍在。是否停止后台工作,需要看代码与组件设计,不是由一个 CSS 值统一决定。
面试速记卡
- display: none:不生成相应布局盒,DOM 不因此自动删除。
- visibility: hidden:保留位置,不绘制;后代可能显式恢复 visible。
- opacity: 0:整体透明,位置、点击与焦点可能仍在。
- 交互隐藏:同时检查指针、键盘与无障碍,不只看截图。
- 安全:隐藏不是权限控制,也不会自动清理计时器和订阅。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →