首页 > 解决方案 > 如何平滑地为圆角矩形的位置和大小设置动画?

问题描述

我正在实现一个“窗格”视图组件。类似于 IntelliJ 或 VSCode,其中每个窗格可以重新排列为不同的行和列。拖放重新排列动作需要一个预览动画:一个围绕屏幕动画的框,显示动作完成后新窗格将插入的位置。

基本上,我需要一个绝对定位的圆角矩形,它可以在屏幕周围流畅地动画。理想情况下,这将是 GPU 加速的。

我的尝试:

尝试没有。1

我只是创建了一个<div>元素并为、 和heightwidth设置了动画。这有效,并允许所有其他 CSS 效果在矩形上工作,如边框和圆边。但是,它不是很快。建议不要直接为位置和大小设置动画,因为它会强制在每一帧上进行重排。topleft

尝试没有。2

相反,我创建了1px by 1pxcoloured ,并通过编辑它的CSS 属性<div>来设置它的大小和位置。transform这是超级平滑的,因为它使用了 GPU 加速的变换属性。但是,它有一个缺点:我无法设置<div>. 我不能使用borderor border-radius,否则它们会被scale转换扭曲。

想法

我的问题- 我怎样才能顺利地在屏幕上为一个 div 设置动画,它的样式是 a borderor border-radius

我可以没有border,但border-radius强烈需要 。

标签: javascripthtmlcssanimation

解决方案


我不完全确定我已经完全理解了这个问题,因为在这种情况下我无法重新创建它:

此代码段使用变换比例和变换平移来为元素设置动画。Evertyhing 是使用 vmin 作为基本单位计算的,因此无论您使用什么设备/视口,您都会看到相同的纵横比。

在我的笔记本电脑上,GPU 使用率非常稳定,为 13%,转换很流畅,我看不到任何失真。那么在原始代码中是否可能使用了一些绝对定义的单元,例如不能正确缩放?

* {
  margin: 0;
  padding: 0;
}

body {
  width: 100vw;
  height: 100vh;
}

.container {
  --containerw: 80vmin;
  --containerh: 60vmin;
  width: var(--containerw);
  height: var(--containerh);
  position: relative;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  position: relative;
  background-color: pink;
}

.test {
  --startleft: 10;
  /* where it starts (within the container as a %) */
  --starttop: 10;
  --endleft: 70;
  /* where you want it to go to (within the container as a %) */
  --endtop: 70;
  --scalex: 4;
  /* how much you want it to grow */
  --scaley: 2;
  --w: 10%;
  /* its width */
  --h: 10%;
  /* its height */
  width: var(--w);
  height: var(--h);
  border-radius: 1vmin;
  border-width: 0.2vmin;
  border-style: solid;
  background-color: cyan;
  animation: move 10s infinite linear;
  position: absolute;
  box-sizing: border-box;
}

@keyframes move {
  0%,
  100% {
    transform: scale(1, 1) translate(calc(var(--startleft) * var(--containerw) / 100), calc(var(--starttop) * var(--containerh) / 100));
  }
  50% {
    transform: scale(var(--scalex), var(--scaley)) translate(calc(var(--endleft) * var(--containerw) / 100 / var(--scalex)), calc(var(--endtop) * var(--containerh) / 100 / var(--scaley)));
  }
}
<div class="container">
  <div class="test"></div>
</div>


推荐阅读