如何平滑地为圆角矩形的位置和大小设置动画?
How to smoothly animate position & size of an rounded rectangle?
我正在实现一个“窗格”视图组件。类似于 IntelliJ 或 VSCode,其中每个窗格都可以重新排列成不同的行和列。拖放重新排列操作需要预览动画:一个在屏幕周围动画的框,显示操作完成后新窗格将插入的位置。
基本上,我需要一个绝对定位的圆角矩形,它可以在屏幕周围流畅地设置动画。理想情况下,这将是 GPU 加速的。
我的尝试:
尝试没有。 1
我只是创建了一个 <div>
元素并为 height
、width
、top
和 left
值设置动画。这有效,并允许所有其他 CSS 效果在矩形上起作用,例如边框和圆角边缘。但是,它不是很快。不建议直接对位置和大小设置动画,因为它会强制在每一帧上重排。
尝试没有。 2
相反,我创建了 1px by 1px
彩色 <div>
,并通过编辑它的 transform
CSS 属性 来设置它的大小和位置。这是 超级 平滑,因为它使用 GPU 加速变换 属性。但是,它有一个缺点:我无法设置 <div>
的样式。我不能使用 border
或 border-radius
,否则它们会因 scale
转换而变形。
想法
- 由于矩形是一个简单的形状,我们可以生成一个
svg
并在不同位置之间进行插值吗?如果这发生在viewBox
之内,会不会很顺利?我不确定这一点,因为我对 SVG 没有太多经验。
我的问题 – 如何在屏幕周围流畅地制作 div 动画,它的样式是 border
或 border-radius
?
我可以没有 border
,但强烈需要 border-radius
。
我不完全确定我已经完全理解了这个问题,因为在这种情况下我无法重现它:
此代码段使用变换缩放和变换转换来为元素设置动画。 Evertyhing 是使用 vmin 作为基本单位计算的,因此无论您使用什么 device/viewport,您都会看到相同的纵横比。
在我的笔记本电脑上,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>
我找到了解决办法!这允许 <div/>
具有圆角和边框的平滑动画(使用 GPU 加速转换),没有任何拉伸。
它基于“边框图像”概念。我们可以对 9 个不同的 div 进行动画处理,而不是对一个 <div/>
进行动画处理,每个 div 代表矩形的一部分。
- 左上角
- 顶部中心矩形
- 右上角
- 左中矩形
- 中间的中心矩形
- 右中矩形
- 左下角
- 底部中心矩形
- 右下角
角不需要缩放,只需要平移。这可以防止任何拉伸。矩形边缘与边框一致,因此不会拉伸 solid
边框。
我正在实现一个“窗格”视图组件。类似于 IntelliJ 或 VSCode,其中每个窗格都可以重新排列成不同的行和列。拖放重新排列操作需要预览动画:一个在屏幕周围动画的框,显示操作完成后新窗格将插入的位置。
基本上,我需要一个绝对定位的圆角矩形,它可以在屏幕周围流畅地设置动画。理想情况下,这将是 GPU 加速的。
我的尝试:
尝试没有。 1
我只是创建了一个 <div>
元素并为 height
、width
、top
和 left
值设置动画。这有效,并允许所有其他 CSS 效果在矩形上起作用,例如边框和圆角边缘。但是,它不是很快。不建议直接对位置和大小设置动画,因为它会强制在每一帧上重排。
尝试没有。 2
相反,我创建了 1px by 1px
彩色 <div>
,并通过编辑它的 transform
CSS 属性 来设置它的大小和位置。这是 超级 平滑,因为它使用 GPU 加速变换 属性。但是,它有一个缺点:我无法设置 <div>
的样式。我不能使用 border
或 border-radius
,否则它们会因 scale
转换而变形。
想法
- 由于矩形是一个简单的形状,我们可以生成一个
svg
并在不同位置之间进行插值吗?如果这发生在viewBox
之内,会不会很顺利?我不确定这一点,因为我对 SVG 没有太多经验。
我的问题 – 如何在屏幕周围流畅地制作 div 动画,它的样式是 border
或 border-radius
?
我可以没有 border
,但强烈需要 border-radius
。
我不完全确定我已经完全理解了这个问题,因为在这种情况下我无法重现它:
此代码段使用变换缩放和变换转换来为元素设置动画。 Evertyhing 是使用 vmin 作为基本单位计算的,因此无论您使用什么 device/viewport,您都会看到相同的纵横比。
在我的笔记本电脑上,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>
我找到了解决办法!这允许 <div/>
具有圆角和边框的平滑动画(使用 GPU 加速转换),没有任何拉伸。
它基于“边框图像”概念。我们可以对 9 个不同的 div 进行动画处理,而不是对一个 <div/>
进行动画处理,每个 div 代表矩形的一部分。
- 左上角
- 顶部中心矩形
- 右上角
- 左中矩形
- 中间的中心矩形
- 右中矩形
- 左下角
- 底部中心矩形
- 右下角
角不需要缩放,只需要平移。这可以防止任何拉伸。矩形边缘与边框一致,因此不会拉伸 solid
边框。