display: none 彻底移除元素,不占空间、不响应事件、触发重排;visibility: hidden 仅隐藏视觉,保留布局和交互,支持子元素覆盖显示。

display: none 和 visibility: hidden 都能让人“看不见”元素,但它们干的事完全不在一个层面上——选错一个,轻则布局跳动、点击穿透,重则读屏器误读、动画失效。
display: none 会彻底删除元素在渲染树中的存在
浏览器构建渲染树时,一旦遇到 display: none,就直接跳过该元素及其所有子节点。它不占空间、不响应事件、getBoundingClientRect() 返回全 0、Tab 键无法聚焦、屏幕阅读器默认跳过。
- 适合真正“抽离”的场景:Tab 切换面板、条件渲染弹窗、表单步骤控制
- 父元素设了
display: none,子元素再写display: block也无效 - 切回显示时会触发重排(reflow)+ 重绘(repaint),频繁切换(如滚动监听中)要小心 layout thrashing
- 不能加
transition: display 0.3s——display不是连续可过渡的属性,写了也白写
visibility: hidden 只是“不画出来”,但元素还在原位
visibility: hidden 发生在绘制阶段,布局照常进行。元素仍占位、尺寸可读、offsetHeight 有值、子元素可通过 visibility: visible 单独显出——这点极易被忽略,导致模态框遮罩下内容“透出”。
- 适合需保留布局结构的微调:悬停显示辅助图标、错误提示默认隐藏但留空位、维持滚动锚点
- 有继承性:父设
visibility: hidden,子默认继承;但子设visibility: visible能覆盖 - 不触发重排,只重绘,性能比
display切换更温和 - 打印样式表中它不影响输出——
display: none才真正不打印
为什么不能混用 display 和 visibility 控制同一元素?
两者作用机制冲突:display: none 让元素从渲染树里消失,visibility 根本没机会生效;但反过来,若某处 CSS 写了 .sidebar { display: block },另一处媒体查询写 .sidebar { visibility: hidden },前者依然生效——因为 display 的“存在性”优先级更高,visibility 被静默忽略。
立即学习“前端免费学习笔记(深入)”;
- 同一元素上避免同时设置
display和visibility,尤其在@media中易被权重覆盖 - 想做渐隐动画?别碰
visibility,它只有visible/hidden两个离散值,必须用opacity+pointer-events: none+aria-hidden - 表单控件(如
input、button)需完全禁用交互时,display: none更可靠;仅临时视觉隐藏且要保持Tab焦点流时,才考虑visibility
真正难的不是写哪行 CSS,而是想清楚你要隐藏什么
是只藏“眼睛看到的部分”,还是连“位置、交互、语义”一并拿掉?漏掉其中一环,后面排查就容易绕远。比如用 visibility: hidden 隐藏登录按钮,用户仍能 Tab 进去并回车提交;用 display: none 切换导航栏,页面内容突然上移造成视觉抖动——这些都不是 bug,是机制使然。


















