【问题标题】:How to smoothly animate position & size of an rounded rectangle?如何平滑地为圆角矩形的位置和大小设置动画?
【发布时间】:2021-07-28 18:09:04
【问题描述】:

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

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

我的尝试:

尝试不。 1

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

尝试不。 2

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

想法

  • 既然矩形是一个简单的形状,我们可以生成一个svg 并在不同位置之间进行插值吗?如果这发生在viewBox 内,会顺利吗?我不确定这一点,因为我对 SVG 没有太多经验。

我的问题 – 如何在屏幕上平滑地设置一个 div 动画,它的样式是 borderborder-radius

我可以不用border,但强烈需要border-radius

【问题讨论】:

  • 既然只有transform才能实现平滑移动动画,svg不能实现平滑移动动画?
  • 1px by 1px 制作div 标签可以制作流畅的动画,而制作border-radius 似乎是个问题。如果在每个角落放置一个圆形四分之一边框怎么办?每当更改 border-radius 值时,每个角边框都会更改每个 border-radius 值。
  • @jacobkim 是的,我就是这么想的 :( 这只是一个想法,以防有一个我不知道的 SVG 技巧。我考虑为每个角落使用自定义剪辑图像(我相信这就是你的建议)但是我仍然需要为圆形四分之一边框的位置设置动画,这会很慢,因为它不能使用transform
  • 您能否在问题中包含您的两次尝试的简单示例,以便我们轻松了解时间在哪里?
  • @haz 无法想象用1px by 1pxdiv 设置动画并调整大小的角度是多么缓慢或多么复杂border-radius!只是想如果div1px by 1pxborder-radius: 50% 被用作拐角边框的线条。那么问题将是边界半径值的路径计算。

标签: javascript html css animation


【解决方案1】:

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

这个 sn-p 使用 transform scale 和 transform translate 来为元素设置动画。 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>

【讨论】:

  • 比较最小尺寸和最大尺寸的边框宽度 - 在100%,边框明显更厚,并且底部和顶部与侧面的厚度不同。圆角也会出现同样的情况,但有点难以看到。在 OSX 上的 Chrome 上查看。 scale 值拉伸元素,而不是调整它的大小。这意味着边框被拉伸,所以如果我定义一个1px 边框,当比例增加时,它可能是5px(例如)。这就是我要解决的问题:(
  • 您是说您不希望边框宽度缩放,但您确实希望元素的高度和宽度缩放(可能以不同的量?)在我的 sn-p 是我缩放整个东西都缩放了边框
【解决方案2】:

我想出了一个解决办法!这样可以为带有圆角和边框的&lt;div/&gt; 提供流畅的动画(使用 GPU 加速的转换),而无需任何拉伸。

它基于“边框图像”的概念。我们可以为 9 个不同的 div 设置动画,而不是为一个 &lt;div/&gt; 设置动画,每个 div 代表矩形的一个切片。

  • 左上角
  • 顶部中心矩形
  • 右上角
  • 左中矩形
  • 中间的矩形
  • 右中矩形
  • 左下角
  • 底部中心矩形
  • 右下角

角不需要缩放,只需平移。这可以防止任何拉伸。矩形边缘与边框对齐,因此不会拉伸solid 边框。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    • 2019-07-11
    • 2019-07-24
    • 2023-03-13
    • 2020-06-20
    • 1970-01-01
    相关资源
    最近更新 更多