CSS 技巧:transition 从`height: 0`到`auto`的过渡

321 阅读2分钟

你可能至少尝试过一次用 transition 从height: 0auto的过渡... 结果发现根本不起作用!😖

让我们从一个例子讲起:

代码非常简单,如果你将鼠标悬停在手风琴上,它将会展开。看起来基本功能已经实现了,但是过渡效果看起来一点也不平滑。

但实际上 CSS 代码中已经加上了height的过渡:

.accordion-body {
  height: 0;
  transition: 500ms height ease;
}

.accordion:hover .accordion-body {
  height: auto;
}

正如开篇说的那样:从height: 0auto的过渡,根本没有任何过渡效果。

那怎样解决呢?🤔

方案一 (fixed height)

height 属性设置为一个固定的数字,而不是auto。 一定程度上这是可行的。但是这不是一个很好的方法:为了计算这个固定的数字,我们被迫使用 javascript 进行计算 dom clientHeight 实际有多么高。 显然这不是我们想要的方案。❎

那有没有一种仅使用 CSS 就可以实现过渡效果的解决方案呢?

方案二 (max-height)

我们可以用 maxheight来解决啊~😄

.accordion-body {
  max-height: 0;
  transition: 250ms max-height ease;
}

.accordion:hover .accordion-body {
  max-height: 200px;
}

现在过渡效果可以正常平滑地过渡了。

唯一的小缺陷:由于为max-height定义了一个固定值,内容可能会溢出。

看起来只要max-height值合适,就可以了。

但是需要注意的是:max-height的值越高,过渡转换就越奇怪。 (不信你在CSS 代码中 把max-height改成 1000px 看看啥效果😁)

难道就没有更加优秀的方案嘛?使得我们一开始就能避开heightmax-height

方案三 (CSS Grid)🎉

用 CSS Grid 创建单个网格项:grid-template-rows 使其从 0fr过渡到1fr。就是如此简单:

.accordion-body {
  display: grid; 
  grid-template-rows: 0fr;
  transition: 250ms grid-template-rows ease;
}

.accordion:hover .accordion-body {
  grid-template-rows: 1fr;
}

.accordion-body-required-container {
  overflow: hidden;
}

很简洁,没有花里胡哨的代码,也按照我们的预期 work 了。

此解决方案需要注意的一点:需要将 overflow: hidden 设置为 .accordion-body 的内部 div 才能使此工作。

原理:基于浏览器的新功能 grid-template-rows 跟踪动画,主流浏览器都支持。生产代码要使用这个特性,一定要先检查兼容性! 😉

💡兼容性caniuse.com/mdn-css_pro…

image.png