display: none 与 visibility: hidden 的区别?
面试速答(30 秒版 TL;DR)
display: none:元素不生成盒子(box),相当于从布局里移除,不占空间;整棵子树都不会渲染,子元素无法“单独显示”。visibility: hidden:元素仍占据布局空间,只是不绘制;visibility是可继承的,子元素可显式设为visibility: visible重新显示。
核心对比(高频维度)
| 维度 | display: none | visibility: hidden |
|---|---|---|
| 是否占位 | ❌ 不占位 | ✅ 占位 |
| 是否生成盒子 | ❌ 不生成(无 box) | ✅ 生成但不可见(不绘制) |
| 命中测试/点击 | ❌ 点不到 | ❌ 点不到(点击会落到后面的元素) |
| 可访问性(屏幕阅读器) | 通常不可 | 通常不可 |
| 对子元素的影响 | 子树整体不渲染,无法被子元素覆盖 | 默认影响子元素,但子元素可设 visibility: visible 覆盖 |
| 读取布局尺寸(常见 DOM API) | offsetWidth/Height 通常为 0 | 仍可读到实际尺寸 |
| 切换开销(一般) | 更可能触发 reflow(布局变化) | 通常不触发布局,只影响绘制 |
| 能否做过渡动画 | 不行(不能平滑过渡到/从 none) | visibility 本身是离散切换,常配合 opacity 做过渡 |
注:上表是常见规律总结。实际是否触发 reflow/paint 仍取决于页面结构与浏览器优化。
代码例子(最小)
<div class="row">
<span class="a">A</span>
<span class="b">B</span>
</div>
.row {
display: flex;
gap: 12px;
}
/* 1) 不占位:B 直接消失,A 会顶上去 */
.b {
display: none;
}
/* 2) 占位但不可见:B 留下空白 */
/* .b { visibility: hidden; } */
常见追问(面试会顺带问)
Q1:那 opacity: 0 呢?
opacity: 0:元素占位,并且默认仍会参与命中测试(也就是“看不见但能点到”)。- 想“透明但不可点”,一般配
pointer-events: none;。 - 想“先渐隐,结束后再彻底移除布局”,常见做法是:先用
opacity过渡,动画结束后再切换display: none(或切换visibility)。
Q2:如何避免隐藏/显示导致布局抖动?
- 需要“保留占位”就用
visibility: hidden(或固定尺寸占位)。 - 需要“完全移除占位”就用
display: none,但它会影响周围布局,属于预期行为。
易错点/坑
visibility: hidden会留空白,可能导致“列表出现一条空行”或“容器滚动高度不对”。visibility是继承属性:父元素hidden时,子元素如果显式写visibility: visible可能会重新显示;想“一刀切”隐藏整个子树,display: none更彻底。