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 也算不可见

 

posted @ 2022-03-02 18:22  兴杰  阅读(454)  评论(0)    收藏  举报