CSS 中数值到关键字的过渡

在 CSS 中,auto 等关键词不是一个具体的数值,无法直接进行动画过渡,本文介绍了一些方式来实现类似的效果。

2024-07-26
2024-10-09

在 CSS 中,auto 等关键词不是一个具体的数值,无法直接进行动画过渡,例如下面的代码并不能产生过渡效果:

.wrapper {
    height: 0;
    transition: height 0.5s;
}

.wrapper.expanded {
    height: auto;
}

不过可以通过以下方式来实现类似的效果。最新的浏览器提案也提到了数值到关键字的过渡问题,并且提出了两种新的解决方案。

一些文章可能会使用足够大的 max-height 来实现,不过这里不推荐使用,因为动画效果不好看。下面介绍一些推荐的方法。

使用 CSS Grid 布局

部分浏览器的 CSS Grid 布局中,grid-template-rows 是支持过渡的,所以可以这样实现高度从 0 到 auto 的过渡。

.wrapper {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.5s;
}

.wrapper.expanded {
    grid-template-rows: 1fr;
}

缺点:兼容性不太好。

使用 JavaScript 动态计算高度

<style>
    .container {
        overflow: hidden;
        height: 0;
        transition: height 0.5s ease-out;
    }

    .container.expanded {
        height: auto;
    }
</style>

<button onclick="toggle()">Toggle</button>
<div id="content" class="container">
    <p>This is some content that will expand and collapse.</p>
    <p>More content...</p>
</div>

<script>
    function toggle() {
        const content = document.getElementById('content');
        if (content.classList.contains('expanded')) {
            content.style.height = content.scrollHeight + 'px';
            requestAnimationFrame(() => {
                content.style.height = '0';
                content.classList.remove('expanded');
            });
        } else {
            content.style.height = content.scrollHeight + 'px';
            content.classList.add('expanded');
            content.addEventListener('transitionend', () => {
                content.style.height = 'auto';
            }, { once: true });
        }
    }
</script>

实现复杂,但是兼容性好。

使用 calc-size()

CSS 的 calc-size() 函数将诸如 auto 之类的值转换为特定的像素值,从而可以用于过渡。

calc-size() 支持以下值:

  • auto
  • min-content
  • max-content
  • fit-content
  • stretch
  • contain
.wrapper {
    height: 0;
    transition: height 0.5s;
}

.wrapper.expanded {
    height: calc-size(auto);
}

calc-size() 预计在 Chrome 129 版本发布。

使用 interpolate-size 全局属性

CSS 的 interpolate-size 属性可以让我们在根元素上设置插值计算的规则,这样针对整个页面都会生效。

interpolate-size 有两个值,一个是 allow-keywords 所有关键字,一个是仅限数字 numeric-only。

  • numeric-only:设置了这个属性之后,如果插值的属性值不是数字的话,就不会产生过渡的效果。

  • allow-keywords:设置了这个属性,只要是合法的属性值,都会插值计算,从而都会产生过渡效果。

html {
    interpolate-size: allow-keywords;
}

.wrapper {
    height: 0;
    transition: height 0.5s;
}

.wrapper.expanded {
    height: auto;
}

interpolate-size 预计在 Chrome 129 版本发布。

参考

W3C 草案
https://drafts.csswg.org/css-values-5/#funcdef-calc-size

WebKit
https://github.com/WebKit/standards-positions/issues/348

https://developer.chrome.google.cn/docs/css-ui/animate-to-height-auto

https://segmentfault.com/a/1190000045102391

文章目录

版权

本文遵循署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0) 标准。

部分内容源自互联网、书本和课堂,仅供交流学习,未用于任何商业用途。如果它们侵犯了您的权益,请与我们联系,我们将立即删除它们。

版权所有 © 2020-2026 Kloudy 保留所有权利.