.invisible 和 .d-none 行为完全不同:前者用 visibility: hidden 保留占位、可访问、事件仍生效;后者用 display: none 彻底移出文档流、不占位、屏幕阅读器跳过、JS 查询 offsetParent 为 null。

直接说结论:用 .invisible 或 .d-none 控制显隐,不是“能不能用”的问题,而是“用错地方会破坏可访问性、布局逻辑或 JS 行为”的问题。别只看效果,得看它动了什么 DOM 层面的东西。
为什么 .invisible 和 .d-none 的行为完全不同
它们都让元素“看不见”,但底层机制天差地别:
-
.invisible本质是visibility: hidden—— 元素还在文档流里,占空间,能被屏幕阅读器读到,所有事件监听(如click)依然生效(只是点不到) -
.d-none对应display: none—— 元素彻底脱离文档流,不占空间,屏幕阅读器跳过,JS 查询getBoundingClientRect()会返回全零,offsetParent为null - 常见错误现象:
.invisible元素被误当“已隐藏”做条件判断,结果 JS 还在监听它的input事件;或者用.d-none隐藏表单控件后,form.checkValidity()仍校验它(因为 DOM 还在),但用户根本看不到提示
.d-none 响应式类(如 .d-md-none)的断点陷阱
响应式可见性类不是“叠加生效”,而是“断点覆盖”。一旦写错顺序或混用,行为就不可预测:
-
class="d-none d-md-block":小屏隐藏,中屏及以上显示 —— 正常 -
class="d-md-none d-none":.d-none无条件生效,覆盖所有响应式类,结果永远隐藏 - 使用场景:需要“仅在平板显示”的 banner,写成
d-sm-none d-md-block d-lg-none是错的 ——d-lg-none在大屏也会生效,导致 banner 在大屏消失;正确写法是d-none d-md-block d-lg-none(先设默认隐藏,再逐级放开) - 兼容性注意:IE11 不支持
display: contents,但.d-none没问题;不过如果你用自定义构建删了display工具类,这些 class 就直接失效
和 v-b-visible 这类 JS 可见性检测指令的根本区别
v-b-visible(Bootstrap-Vue)或 IntersectionObserver 原生 API 判断的是“是否进入视口”,而 .invisible/.d-none 是“是否被 CSS 强制隐藏”——二者维度不同,不能互相替代:
- 一个元素加了
.d-none,v-b-visible的回调永远不会触发true,因为 DOM 被移出渲染树,IntersectionObserver根本观测不到它 - 如果用
.invisible隐藏,v-b-visible仍可能返回true(只要它在视口内),但用户看不到 —— 这会导致“懒加载图片已触发,但图始终不显示”的假死现象 - 性能影响:
.d-none完全不渲染,开销最低;v-b-visible需要维护 observer 实例,大量元素监听时要注意 disconnect 时机,否则内存泄漏
真正容易被忽略的点:Visibility 类不是“开关”,而是“CSS 声明”。它不改变元素的语义角色(role)、表单有效性(validity)或焦点管理(tabindex)。想让隐藏元素彻底退出交互链路,得配 aria-hidden="true"、tabindex="-1",甚至手动 remove() —— 单靠 class 解决不了。











