display: none会彻底移除元素,不占空间、触发重排,子元素不可见,屏幕阅读器忽略;visibility: hidden仅视觉隐藏、保留占位、只触发重绘,子元素可设visible单独显示。

display: none 会彻底移除元素,不占空间、触发重排
当你设 display: none,浏览器在布局阶段就跳过该元素:它没有尺寸、没有位置、不参与任何计算。后续兄弟元素会立刻上移补位,offsetHeight 和 getBoundingClientRect() 返回 0。display: none 触发 reflow(重排),开销比 visibility: hidden 高得多。
常见错误现象:在循环中反复读取 offsetHeight 再设 display: none,极易引发 layout thrashing;用它隐藏弹窗后又想通过 JS 获取原尺寸,结果全是 0。
- 子元素无论设置
display: block还是visibility: visible,一律不可见 - 屏幕阅读器默认跳过
display: none元素,无障碍支持更干净 - 事件监听器完全不触发——元素已不在事件捕获/冒泡路径中
visibility: hidden 保留占位,仅视觉隐藏、只触发重绘
visibility: hidden 不改变文档流:元素宽高、margin、padding 全部照常存在,周围布局纹丝不动。它只让内容“变透明”,但依然能被 JS 正确读取尺寸,offsetHeight 返回真实值。
容易踩的坑:忘了 visibility 是继承属性。父级设了 visibility: hidden,子元素若没显式设 visibility: visible,就会跟着消失——但只要设了,就能单独显示出来。
立即学习“前端免费学习笔记(深入)”;
- 鼠标事件仍会捕获(哪怕看不见),要彻底禁用需加
pointer-events: none - 适合做悬停提示(tooltip)预占位、下拉菜单过渡动画等需要布局稳定的场景
- 不会导致 layout thrashing,频繁切换比
display更安全
两者同时设置时,display 优先级更高
CSS 层叠规则里,display: none 的存在直接让元素退出渲染树,此时 visibility: visible 完全无效。反过来,display: block + visibility: hidden 就是标准的“占位隐藏”组合。
实际开发中有人用这个组合做性能优化:先用 display: none 快速清空区域,再用 visibility: hidden + opacity: 0 做渐隐动画——但要注意,动画期间不能切回 display: none,否则动画中断。
- 别用
opacity: 0替代二者:它既占位又响应事件,语义完全不同 - 服务端渲染或 SSR 场景下,
display: none更利于初始 HTML 精简;CSR 动态控制则优先考虑visibility的稳定性
怎么选:看你要“删掉”还是“盖住”
如果目标是条件性移除(比如表单步骤切换、权限控制隐藏模块),选 display: none;如果只是临时遮罩、需要保留布局锚点或频繁切换,选 visibility: hidden。
最易被忽略的一点:当用 JS 控制显隐时,display 切换会强制浏览器同步计算新布局,而 visibility 只改绘制层。前者在复杂 DOM 中可能卡顿,后者更“静默”。但如果你依赖子元素显隐能力,又忘了重置继承链,visibility 反而会暴露不该显示的内容。


















