先记住这个答案
display: none 让元素不生成盒子,它和所有后代都从布局里消失,不占任何空间,周围的元素会补上它的位置。visibility: hidden 的盒子照常生成,宽高和位置都还在,只是不画出来,旁边的元素不会动。所以切换 display 会引起重排,也就是重新计算布局;切换 visibility 布局不变,一般只需要重绘。两者还有两个常考差别:visibility 是继承属性,子元素可以设 visible 单独显示出来;visibility 能参与过渡动画,display 以前不能。
display: none不占位,切换会触发重排visibility: hidden保留占位- 子项可设
visible重新显示 - 两者都点不到,读屏软件也都读不到
占位的差别一眼就能看出来
同样隐藏中间那一项,列表的样子完全不同。
<ul>
<li>第一项</li>
<li style="display: none">第二项</li> <!-- 不占位,第三项顶上来 -->
<li>第三项</li>
</ul>
<ul>
<li>第一项</li>
<li style="visibility: hidden">第二项</li> <!-- 占位,留出一行空白 -->
<li>第三项</li>
</ul>第一个列表看起来只有两项,第三项紧跟在第一项后面。第二个列表中间空了一行,第三项还在原来的位置。
这个差别也决定了重排范围。display 从 none 切到 block,元素的尺寸从无到有,它后面的兄弟、父元素的高度都可能变,浏览器要重新算这一片的布局。visibility 切换时盒子尺寸没变,只要把这块区域重新画一遍。
除了占位,还有哪些不同
占位和重排是最常被问到的,但实际项目里选哪个,往往取决于下面三个差别。
- 子元素能不能单独显示
visibility是继承属性。父元素hidden,子元素默认继承hidden,但子元素自己写visibility: visible就能显示出来。display: none做不到,父元素没有盒子,后代写什么都不会显示。下拉菜单、树形组件里偶尔会用到这个特性。- 过渡动画
visibility可以参与transition,常见写法是和opacity一起过渡:淡出时先把透明度降到 0,最后一刻再切成hidden,这样淡出动画能播完,隐藏后也点不到。display以前是完全不能过渡的,切成none就瞬间消失。新版浏览器开始支持配合transition-behavior: allow-discrete过渡display,但兼容性还要看目标浏览器。- 事件和无障碍
- 两者隐藏后都不响应鼠标点击,也都会从无障碍树里移除,读屏软件读不到。
opacity: 0不一样,元素透明了但还能点、还能被读出来,这是它常被误用成「隐藏」的坑。
场景怎么选
需要彻底移除、让出空间的,用 display: none,比如 Tab 切换里没选中的面板、折叠起来的菜单。
需要保留位置、防止布局跳动的,用 visibility: hidden,比如加载中先占住按钮的位置,或者表格里某列暂时没有数据。
需要淡入淡出的,用 opacity 配合 visibility 过渡,动画结束后元素既看不见也点不到。
容易答错的地方
- 以为
visibility: hidden完全不影响性能 - 它省掉的是重排,重绘还是有的。而且元素仍然参与布局计算,页面上藏着大量
hidden元素时,布局成本一点没少。 - 以为
display: none的元素能量出尺寸 - 它没有盒子,
offsetHeight、getBoundingClientRect()读出来都是 0。做高度动画时要先把它设成可见状态再量,或者用visibility: hidden配合绝对定位先离屏量好。 - 以为
display: none的元素里的图片不会加载 <img>标签即使在display: none的容器里,浏览器一般也会照常下载图片。真正省流量要靠不渲染这段 DOM,或者用loading="lazy"。
面试官还会怎么问?
Vue 的 v-show 和 v-if 分别对应哪种?
v-show 切换的是 display: none,DOM 一直在;v-if 直接创建和销毁 DOM。切换频繁用 v-show,条件很少变化或者初始不需要渲染时用 v-if。
visibility: collapse 是什么?
它主要用在表格行和列上,效果类似把这一行从表格里去掉,但表格的列宽等计算仍然考虑它。用在普通元素上时,表现和 hidden 一样。
为什么说切换 class 比逐条改 style 好?
逐条改 style.display、style.width 并且中间读取布局属性,会让浏览器反复重排。把样式写进 class 一次切换,浏览器可以把多项修改合并成一次布局计算。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。