各位网友大家好,之前我己为大家介绍了0到auto的过渡,其核心是 height:calc-size(auto,size)
css
.collapsible{
overflow-y: hidden;
}
.hide {
display: none;
}
@media (prefers-reduced-motion: no-preference) {
@supports (height: calc-size(auto, size)) {
/* 展开状态 */
.collapsible {
height: calc-size(auto, size);
transition: height .3s;
}
/* 折叠状态 */
.collapsible.hide {
display: block;
height: 0;
}
}
}

在线演示 linsk1998.github.io/ting/compon...
上面代码表面上能用,但是有两个边界场景
- 首先容器含有overflow:hidden,会导致内部内容被截断,如果内部内容还有box-shadow,很容易被截掉。最好是只在过渡时含有overflow:hidden。
- 还有收起后应当含有disaplay:none,否则收起后仍然占据体积,在一些情况下会出现不必要的滚动条。比如下图的这个树形组件,折叠后由于仍然占据体积,水平滚动条并没有消失。

上述问题可以用animation或@starting-style解决。但是又产生了新的问题------------初始动画。

有没有一种技巧,只在用户操作时才播放过渡效果?
没有通用解法,但是特定dom结构可以实现。
比如上面的树形组件,我们可以用展开按钮的:focus伪类来实现
css
@media (prefers-reduced-motion: no-preference) {
@supports (height: calc-size(auto, size)) {
.tree li {
min-width: fit-content;
}
.tree .tree-collapsible{
height: calc-size(auto, size);
overflow: hidden;
transition: height 0s, display 0s allow-discrete;
}
.collapsed>.tree-collapsible{
height: 0;
display: none;
}
@starting-style {
.tree .tree-collapsible{
height: 0;
}
}
.tree-toggler:focus ~ .tree-collapsible{
transition-duration: .3s;
}
}
}

在线演示 linsk1998.github.io/ting/compon...
原理拆解一下:
- 默认情况下
transition-duration: 0s,此时无论样式如何变化,视觉上都是瞬时完成,不会播放任何动画------包括页面加载时的初始动画。 - 当用户点击
.tree-toggler按钮时,按钮获得:focus,相邻兄弟选择器~命中.tree-collapsible,过渡时长被替换成.3s,于是展开/折叠就带上了平滑的过渡。 - 配合
display 0s allow-discrete和@starting-style,display: none与高度过渡可以无缝衔接,彻底消除折叠后残留的占位问题。