css 动画中的反变换
Counter transform in css animation
在某些界面中,我想做动画。由于变换 属性 比其他 CSS 属性更优化,我将使用它。
使用 transform: scale() :当元素纵横比不变时,没问题。当比率应该改变时,我找到的解决方案是放置一个容器,并在这个容器中放置一个内部容器。然后将相反的变换应用到内部块,以便在动画期间和之后保留比例。
我做了一个笔来测试这个想法,它有效,但在动画过程中有一个问题:在动画过程中内部块看起来被拉伸了。我不明白为什么动画时间是相同的,缓动是线性的。
https://codepen.io/AdamElio/pen/PabejP
(点击菜单切换动画)
document.querySelector('#menu').addEventListener('click', function() {
this.classList.toggle('collapsedd')
});
#menu {
margin: 30px;
padding: 15px;
background: white;
width: 150px;
overflow: hidden;
transform-origin: top center;
transition: transform .5s linear;
}
#menu.collapsedd {
transform: scaleY(.2);
}
#menu .inner {
transition: transform .5s linear;
transform-origin: top center;
}
#menu.collapsedd .inner {
transform: scaleY(5);
}
#menu .inner ul {
padding: 0;
margin: 0;
list-style: none;
}
<nav id="menu">
<div class="inner">
<h5>Menu</h5>
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
</ul>
</div>
</nav>
<div id="transform"></div>
我认为是因为这一行:
#menu.collapsedd .inner {
transform: scaleY(5);
}
添加 collapsedd 后,您正在将内容的 Y 缩放为 5,尝试将该值更改为 1,或者只是不对内部 div 进行缩放。您可以使用不透明度或其他方式使其淡出吗?
发生这种情况是因为在转换发生时计数器转换不相同。考虑到您的示例,容器将从 scaleY(0.2)
变为 scaleY(1)
,而 child 将从 scaleY(5)
变为 scaleY(1)
。
在转换的结束和开始时这将起作用,因为容器和 child 转换将 "cancel out":
- 开始:0.2 * 5 = 1
- 结束:1 * 1 = 1
但是过渡的中间步骤就不是这样了。例如,当转换完成 50% 时:
- 容器比例Y:0.2 + (1 - 0.2) * 0.5 = 0.6
- child 比例 Y: 5 + (1 - 5) * 0.5 = 3
- 容器 scaleY * child scaleY: 0.6 * 3 = 1.8
查看下图以了解该比例的变化情况:
紫色线表示过渡期间child的scaleY,蓝色线表示容器的scaleY,深黄色线表示容器scaleY * child scaleY
因此,为了在过渡期间真正取消容器变换,您需要使用一个缓动函数来保存整个过渡的表达式 container scale * child scale = 1
。这不是一件容易的事。
在某些界面中,我想做动画。由于变换 属性 比其他 CSS 属性更优化,我将使用它。
使用 transform: scale() :当元素纵横比不变时,没问题。当比率应该改变时,我找到的解决方案是放置一个容器,并在这个容器中放置一个内部容器。然后将相反的变换应用到内部块,以便在动画期间和之后保留比例。
我做了一个笔来测试这个想法,它有效,但在动画过程中有一个问题:在动画过程中内部块看起来被拉伸了。我不明白为什么动画时间是相同的,缓动是线性的。
https://codepen.io/AdamElio/pen/PabejP
(点击菜单切换动画)
document.querySelector('#menu').addEventListener('click', function() {
this.classList.toggle('collapsedd')
});
#menu {
margin: 30px;
padding: 15px;
background: white;
width: 150px;
overflow: hidden;
transform-origin: top center;
transition: transform .5s linear;
}
#menu.collapsedd {
transform: scaleY(.2);
}
#menu .inner {
transition: transform .5s linear;
transform-origin: top center;
}
#menu.collapsedd .inner {
transform: scaleY(5);
}
#menu .inner ul {
padding: 0;
margin: 0;
list-style: none;
}
<nav id="menu">
<div class="inner">
<h5>Menu</h5>
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
</ul>
</div>
</nav>
<div id="transform"></div>
我认为是因为这一行:
#menu.collapsedd .inner {
transform: scaleY(5);
}
添加 collapsedd 后,您正在将内容的 Y 缩放为 5,尝试将该值更改为 1,或者只是不对内部 div 进行缩放。您可以使用不透明度或其他方式使其淡出吗?
发生这种情况是因为在转换发生时计数器转换不相同。考虑到您的示例,容器将从 scaleY(0.2)
变为 scaleY(1)
,而 child 将从 scaleY(5)
变为 scaleY(1)
。
在转换的结束和开始时这将起作用,因为容器和 child 转换将 "cancel out":
- 开始:0.2 * 5 = 1
- 结束:1 * 1 = 1
但是过渡的中间步骤就不是这样了。例如,当转换完成 50% 时:
- 容器比例Y:0.2 + (1 - 0.2) * 0.5 = 0.6
- child 比例 Y: 5 + (1 - 5) * 0.5 = 3
- 容器 scaleY * child scaleY: 0.6 * 3 = 1.8
查看下图以了解该比例的变化情况:
紫色线表示过渡期间child的scaleY,蓝色线表示容器的scaleY,深黄色线表示容器scaleY * child scaleY
因此,为了在过渡期间真正取消容器变换,您需要使用一个缓动函数来保存整个过渡的表达式 container scale * child scale = 1
。这不是一件容易的事。