display: none 彻底移除元素并触发重排,visibility: hidden 仅隐藏但保留布局位置且只触发重绘;前者不可继承、子元素不可见,后者可继承且子元素可设为可见;两者均阻止鼠标事件,但仅后者支持 focus()。

display: none 和 visibility: hidden 都能隐藏元素,但效果完全不同
关键区别在于:display: none 让元素彻底退出文档流,不占空间;visibility: hidden 只让元素“不可见”,仍占据原有布局位置。
元素是否参与页面布局(重排)
这是最直接影响渲染行为的差异:
-
display: none:元素从渲染树中移除,父容器会重新计算尺寸和子元素位置(触发 重排(reflow)) -
visibility: hidden:元素保留在渲染树中,仅跳过绘制阶段(只触发 重绘(repaint),不重排) - 如果频繁切换,
visibility: hidden性能通常更好(尤其在动画或列表折叠场景) - 用
getComputedStyle(el).display或getComputedStyle(el).visibility可验证当前状态
子元素能否被显示或交互
继承性与事件响应行为不同:
-
visibility: hidden是可继承的 —— 子元素默认也隐藏,但可通过设置visibility: visible单独显示子元素 -
display: none不可继承,且子元素无论如何设置display都不会显示(父级已脱离渲染树) - 两者都会阻止鼠标事件(如
click、hover),但visibility: hidden元素仍可被focus()(若本身可聚焦),而display: none元素无法获得焦点
实际使用时容易踩的坑
很多 bug 源于混淆二者语义:
立即学习“前端免费学习笔记(深入)”;
- 用
visibility: hidden实现“抽屉菜单”会导致空白占位,用户滚动时看到大片空隙 - 用
display: none控制表单字段显隐,再用querySelector查找时可能返回null(因为 DOM 节点还在,但渲染树里没了) - 屏幕阅读器对二者的处理不同:
display: none默认忽略该元素;visibility: hidden仍可能被读出(需配合aria-hidden="true") - 动画不能直接对
display属性做过渡(CSStransition对display无效),但可以对visibility+opacity组合做渐隐
/* 安全的渐隐方案示例 */
.fade-out {
visibility: hidden;
opacity: 0;
transition: opacity 0.3s, visibility 0.3s;
}
.fade-in {
visibility: visible;
opacity: 1;
}有些细节必须动手测:比如 offsetHeight 在 display: none 下为 0,而 visibility: hidden 下仍返回真实值。别只看视觉表现。











