配了八年折叠动画,每次 height:0→auto 都要靠 JS 硬撑——今天 CSS 自己会了,interpolate-size 把这件事彻底原生化了

我配手风琴配了八年,每次展开收起都要靠 JS 套一层 max-height 才能勉强做动画——今天发现 CSS 自己会量了,interpolate-size: allow-keywords 把这件事彻底原生化了。

interpolate-size 是 Chrome 129 进入 Baseline 2024 的一个新属性,它的核心能力只有一个:允许 CSS 在「关键字尺寸」和「固定尺寸」之间做插值。什么叫关键字尺寸?height: auto、height: contain、width: min-content,这些都是浏览器自己算出来的值,传统上是不支持动画的。

举个例子。传统做折叠动画:

/* 效果是啥?没有动画,直接跳 */
.accordion-content {
  height: 0;
  overflow: hidden;
  transition: height 0.3s;
}
.accordion-content.open {
  height: auto; /* 浏览器:auto 怎么过渡?算不了,跳帧 */
}

这行 height: auto 放在 transition 后面,浏览器直接放弃治疗——auto 是多少它不知道,过渡动画自然做不了。

三行代码,彻底解决这个坑。

.accordion-content {
  height: 0;
  overflow: hidden;
  interpolate-size: allow-keywords;   /* 第一行:允许关键字尺寸参与插值 */
  transition: height 0.3s,            /* 高度本身过渡 */
              visibility 0.3s;        /* visibility 也配合过渡 */
  transition-behavior: allow-discrete; /* 第三行:允许离散的属性(display/visibility)参与过渡 */
}
.accordion-content.open {
  height: auto;
  visibility: visible;
}

加上这三行之后,Chrome 129+ 浏览器就能把 height: 0 到 height: auto 之间的差值算出来,然后老老实实做动画了。

这是怎么工作的? 传统 transition 只支持数值到数值的插值(100px → 200px)。interpolate-size: allow-keywords 相当于给浏览器下了一个指令:「当遇到 auto、min-content、max-content 这些关键字时,自己去把它们的计算值算出来,然后参与插值。」浏览器会在动画开始前把目标尺寸预先算好,动画过程中实时插值,结束前再把真实值还原回去。

配合 @starting-style 做入场动画。 如果想在元素刚出现时也加一个从隐藏到显示的过渡,需要加上 @starting-style:

.accordion-content {
  interpolate-size: allow-keywords;
  transition: height 0.3s, visibility 0.3s;
  transition-behavior: allow-discrete;
}
.accordion-content.open {
  height: auto;
  visibility: visible;
}
/* 元素刚显示时的初始样式,配合 @starting-style */
@starting-style {
  .accordion-content.open {
    height: 0;
  }
}

配合 details/summary 做纯 HTML 手风琴。 如果你用的是原生 <details>/<summary> 组合,连 JS 都可以不要:

<details name="accordion">
  <summary>第一项</summary>
  <p>展开内容</p>
</details>
<details name="accordion">
  <summary>第二项</summary>
  <p>展开内容</p>
</details>
details {
  interpolate-size: allow-keywords;
  transition: height 0.3s, visibility 0.25s;
  transition-behavior: allow-discrete;
}
details[open] {
  height: auto;
  visibility: visible;
}
/* exclusive 行为:一个打开另一个自动关闭 */
@starting-style details[open] {
  height: 0;
}

加了 name=”accordion” 之后,<details> 会自动实现「同时只展开一个」的排他行为,这是原生支持的,不需要任何 JS。

兼容性现状。 interpolate-size: allow-keywords 目前只有 Chrome 129+ 支持,Firefox 和 Safari 还没上。生产环境使用时一定要加 @supports 渐进增强:

.accordion-content {
  height: 0;
  overflow: hidden;
}
@supports (interpolate-size: allow-keywords) {
  .accordion-content {
    interpolate-size: allow-keywords;
    transition: height 0.3s, visibility 0.25s;
    transition-behavior: allow-discrete;
  }
  .accordion-content.open {
    height: auto;
    visibility: visible;
  }
}

不支持的浏览器会回退到没有动画的切换体验——这是可接受的降级方案。

下一步,你可以这样做。

  1. 把项目里所有套了 max-height hack 的手风琴组件找出来,换成这三行 CSS
  2. 如果你在用 React/Vue,手风琴的展开状态可以继续用状态管理,只需要把动画逻辑交给 CSS
  3. 在 caniuse.com 上关注 Firefox 和 Safari 的支持进度,一旦上 Baseline 2025,就可以全面推广

八年了,height: auto 的过渡动画终于不用再靠 JS 了。CSS 正在把那些「本来就应该浏览器自己会」的事情,一件一件还给我们。

评论区

0 条评论

登录后可评论。

小鹿·界面实验室 254 阅读