CSS – display, visibility, opacity, content-visibility, transparent 的区别
前言
要让一个元素 "消失",有 4 种做法。它们有一点点的不同,在实战时要清楚什么时候用什么哦。
例子说明
<div class="abc"> <div class="xyz"></div> </div>
CSS Style
.abc { border: 1px solid red; width: max-content; .xyz { width: 100px; height: 100px; background-color: red; } }
效果

opacity: 0
opacity 是让元素透明. 虽然看不到, 但是占据空间, 同时可被触碰 (e.g. hover).
.xyz { opacity: 0; &:hover { opacity: 1; } }
效果

虽然看不见, 但是占据空间, 而且可以 hover.
冷知识 – Transform, Opacity 也会让元素飘起来
visibility: hidden
它比 opacity 厉害一点, 看不见, 同时也触碰不到了, 但依然占据空间.
.xyz { visibility: hidden; &:hover { visibility: visible; } }
效果

已经 hover 不到了, 但它依然占据空间.
display: none
它才是真正让元素消失的, 看不见, 不占空间, hover 不到.
.xyz { display: none; &:hover { display: block; } }
效果

由于不占据空间了, 只剩下 container 的 1px border. 所以只看见小红点.
另外不占空间也意味着 dimension 是 0,比如 element.offsetWidth 会返回 0,还有 getBoundingClientRect top, left, width, height 都会返回 0。
content-visibility: hidden
参考:使用 content-visibility 优化渲染性能
content-visibility 比较新,要 IOS 18 才支持。
顾名思义,它是用来控制 element 内容 (content) 是否可见的。
visibility: hidden 是让 element 不可见。
content-visibility: hidden 是让 element 的内容不可见,但 element 本身是可见的。
HTML
<div class="container"> <h1>Hello World</h1> </div> <footer>footer</footer>
CSS
.container { background-color: red; width: 100px; height: 100px; content-visibility: hidden; h1 { font-size: 24px; } }
效果

container 本身是可见的,但其内容 h1 则不可见。
另外,它这个不可见效果建于 display: none 和 visibility: hidden 之间,怎么说呢?
.container { content-visibility: hidden; h1 { font-size: 24px; } }
效果

看,container 的 height 是 0,不占据任何空间。
假如我们使用 visibility: hidden 则 container height 为 27px
.container { h1 { font-size: 24px; visibility: hidden; } }
效果

从这个 hidden 效果上看,它像是 display:none。
但,它和 display:none 任然有不同。
假如我们使用 getBoundingClientRect 获取高度
h1.getBoundingClientRect().height; // 27
我们是可以拿到 h1 高度的。(注:container 的高度是 0,但 h1 是可以拿到 27px 的)
假如我们使用 display:none 的话,container 和 h1 的高度都将会是 0。
是不是挺奇葩的😔...
content-visibility: auto
content-visibility: hidden 比较少会用到,我们日常用的是 auto。
它主要用于性能优化。
游览器会先 hidden,等用户滚动到该区域,它会变成 visible,当用户离开该区域,它又 hide 回去。
此外,它还有一个特色,用户 ctrl + f 可以查找到被 content-visibility: auto 隐藏起来的内容。
注:auto 才找得到,hidden 则找不到。
搭配 contain-intrinsic-size
上面我们提到,container 的 height 是 0,滚动到该区域 visible 之后才会有 height。
这会导致用户一边 scroll,页面内容 (高度) 一边增加,会有一种跳跳跳的体验。
这不好,所以我们需要搭配 contain-intrinsic-size: 100px 来设置一个 extimate height 给 container。
这样就不会一边 scroll 一边跳了。
和 lazyloading 的关系
没什么关系,content-visibility: auto / hidden,内容只是不可见,但假如有 <img> 它任然会去加载,lazyloading 我们要另外设置。
总结
opacity 看不见, 占空间, 能触碰 (re-paint)
visibility 看不见, 占空间, 不能触碰 (re-paint)
display: 看不见, 不占空间, 不能触碰 (re-flow)
content-visibility 本身看得见,但子孙 element 看不见,不占空间,不能触碰 (re-flow)。
fade in 效果
display none 转换 display: block 是没有 transition 效果的.
所以通常用 visibility + opacity 来实现 fade in. 但要注意空间的问题, 因为 visibility 是占据空间的.
有时候会用 height: 0 来帮助消失空间. 但也要注意 height: 0 的冷知识 哦.
hamburger menu 的消失 (transparent)

中间是一个 div / span, 然后加上 ::before, ::after 就成了 hamburger
打开的 menu 的时候会变成 X 中间那一条会消失. 上面 3 种方式都做不到这个效果. 因为 opacity 会把整个 div 消失掉. 也包括了里面的 ::before, ::after.
正确的做法是通过 background-color: transparent, 这样中间就消失了, 但是 "内容" ::before 和 ::after 则依然在.
checkVisibility
checkVisibility 是一个比较新的功能,要 IOS 17.4 才支持。
它能检测出一个 element 当前是否可见。
console.log(element.checkVisibility()); // false
返回 false 就是不可见。
它检测的标准是 display: none 这种等级的才算不可见。
<div class="container"> <h1>Hello World</h1> </div>
console.log(h1.checkVisibility()); // 检测 h1
1. container display: none 就不可见
2. h1 display: none 也不可见
3. container content-visibility: hidden 也算不可见

浙公网安备 33010602011771号