不幸的是,对此没有特别优雅的方法。
关于帖子标题中的问题,一种常见的方法是对height
新元素进行动画处理。如果您不知道元素的高度,不幸的是,动画 from 0px
toauto
尚未起作用,但您可以通过将max-height
from动画0px
设置为略大于您期望元素的最大尺寸的值来伪造它。
但不要那样做。
它将导致浏览器在每个动画帧上布局页面,并且几乎肯定会在低端设备上卡顿。
相反,您最好制作动画transform
。
最常见的方法是:
在将新元素添加到 DOM之前getBoundingClientRect()
获取将受到影响的元素的原始位置(使用等)(可能使用,除非您使用钩子,在这种情况下,您可以使用类似的效果)。getSnapshotBeforeUpdate
useRef
添加新元素后(您可能还通过使用transform
合适的scale()
函数对其进行动画处理),计算偏移元素现在所在位置与它们过去所在位置相比的增量。
设置transform
从增量的负值到零的动画(即 FLIP 方法)。例如,如果元素已在页面下方移动了 300px,则动画transform
从translateY(-300px)
到none
。
当然,您需要对流中受影响的所有元素执行此操作,因此将它们全部放在一个容器中并为其设置动画可能是最简单的。
关于第三点,您有几种技术选择,但都不是很好:
CSS 过渡。这些是最简单的,但您必须触发样式刷新才能使负增量起点保持不变。例如
elem.style.transform = `translateY(-${offset}px)`;
elem.style.transition = `transform .3s`;
getComputedStyle(elem).transform; // Flush style
elem.style.transform = `none`;
CSS 动画。使用 CSSOM 动态生成@keyframes
规则是一件痛苦的事情,但至少您不需要触发样式刷新(并且您可以为方便设置一个带有隐式 to-keyframe 的动画)。
@keyframes random-id { from: { translateY(-300px); } }
网络动画。这可能是最合适的。
elem.animate({ transform: [ `translateY(-${offset}px)`, 'none' ] }, 300);
// In future when browsers ship support for implicit to/from keyframes:
elem.animate({ transform: `translateY(-${offset}px)`, offset: 0 }, 300);
不幸的是,Safari 在 Tech Preview 中仅支持 Web 动画,因此 Safari 用户将在下一个 Safari 版本之前获得非动画版本。在基于 Chromium 的 Edge 发布之前,Edge 用户还将获得非动画版本。也有一个polyfill,但目前还没有积极维护。
如果你使用 React,Animating the Unanimatable是一篇很有帮助的文章。
另一个棘手的部分是确保滚动不会跳转,您可能需要查看滚动锚定。