嵌套的css比例变换转换不会相互抵消

时间:2016-07-13 14:45:50

标签: css css3 css-transforms

我的图像根据概览/细节状态更改其高度。它必须是background-size: cover的背景图像,以确保始终覆盖容器。

由于转换需要具有高效性,除了在内部元素上的包装元素和相应的转换transform: scaleY(0.5)上使用transform: scaleY(2)之外别无其他方法,即取消缩放效果。

在开始和结束时,数学是正确的。但是,过渡看起来是错误的。 我准备了一个小小的小提琴来说明出了什么问题:

Codepen - Fiddle

正如您所看到的那样,过渡虽然是线性的,但并不完全相互抵消。我认为存在潜在的数学问题,但我似乎无法找到解决方案。

3 个答案:

答案 0 :(得分:5)

外部元素在scaleY(1)scaleY(0.5)之间进行插值。

t时间,转化将为scaleY(1-t/2)

      t = 0                    t                     t = 1s
┌               ┐      ┌               ┐       ┌               ┐
│ 1   0   0   0 │      │ 1   0   0   0 │       │ 1   0   0   0 │
│ 0   1   0   0 │      │ 0 1-t/2 0   0 │       │ 0  1/2  0   0 │
│ 0   0   1   0 │      │ 0   0   1   0 │       │ 0   0   1   0 │
│ 0   0   0   1 │      │ 0   0   0   1 │       │ 0   0   0   1 │
└               ┘      └               ┘       └               ┘

内部元素在scaleY(1)scaleY(2)之间进行插值。

t时间,转化将为scaleY(1+t)

      t = 0                    t                     t = 1s
┌               ┐      ┌               ┐       ┌               ┐
│ 1   0   0   0 │      │ 1   0   0   0 │       │ 1   0   0   0 │
│ 0   1   0   0 │      │ 0  1+t  0   0 │       │ 0   2   0   0 │
│ 0   0   1   0 │      │ 0   0   1   0 │       │ 0   0   1   0 │
│ 0   0   0   1 │      │ 0   0   0   1 │       │ 0   0   0   1 │
└               ┘      └               ┘       └               ┘

然而,相对于外部而言。从绝对意义上讲,矩阵乘以:

      t = 0                    t                     t = 1s
┌               ┐   ┌                      ┐   ┌               ┐
│ 1   0   0   0 │   │ 1     0      0     0 │   │ 1   0   0   0 │
│ 0  1*1  0   0 │   │ 0 1+t/2-t²/2 0     0 │   │ 0  2/2  0   0 │
│ 0   0   1   0 │   │ 0     0      1     0 │   │ 0   0   1   0 │
│ 0   0   0   1 │   │ 0     0      0     1 │   │ 0   0   0   1 │
└               ┘   └                      ┘   └               ┘

然后,是的,起点和终点对应于单位矩阵。

但在两者之间你有抛物线scaleY(1+t/2-t²/2)

enter image description here

使用贝塞尔曲线可能会达到预期的效果。

f(t)g(t)分别成为.outer.inner的时间函数。

根据定义,f(0) = g(0) = 0f(1) = g(1) = 1

外部的比例将由

给出
( 1-f(t)/2 ) ( 1+g(t) ) = 1 + g(t) - f(t)/2 - f(t)g(t)/2

我们希望它为1,所以

f(t) = 2 g(t) / (1+g(t))
f'(t) = 2 g'(t) / (1+g(t))^2
f'(0) = 2 g'(0)
f'(1) = g'(1) / 2

也就是说,外部的起始斜率必须是内部的两倍,反之则是结束斜率。

选择f(t) = t(线性)和g (.3, 0.15), (.7, .4)给出的贝塞尔曲线似乎可以产生良好的效果。请注意g'(0) = 2 = 2 f'(0)g'(1) = 1/2 = 1/2 f'(0)



.outer, .inner, .inner-expectation {
  transition: transform 2s;
  height: 400px;
}
.outer, .inner {
  transition-timing-function: linear;
}
.inner {
  transition-timing-function: cubic-bezier(.3, 0.15, .7, .4);
}
.inner {
  background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Souq_Waqif%2C_Doha%2C_Catar%2C_2013-08-05%2C_DD_107.JPG/1920px-Souq_Waqif%2C_Doha%2C_Catar%2C_2013-08-05%2C_DD_107.JPG);
  background-size: cover;
}
a:hover ~ .outer {
  transform: scaleY(0.5);
}
a:hover ~ .outer .inner {
  transform: scaleY(2);
}
* {
  box-sizing: border-box;
}
a {
  display: block;
  position: absolute;
  top: 0;
  left: 200px;
  padding: 20px;
  background: wheat;
}
.text {
  position: absolute;
  top: 0;
  height: 100%;
}
.outer {
  background: #fcf8b3;
  position: absolute;
  top: 80px;
  left: 200px;
  width: 400px;
  height: 400px;
}
.inner, .inner-expectation {
  position: absolute;
  width: 300px;
  top: 0;
  left: 100px;
}
.inner .text, .inner-expectation .text {
  right: 0;
}
.inner-expectation {
  width: 20px;
  top: 80px;
  left: 610px;
  background: rgba(255, 0, 0, 0.5);
}

<a href="#">hover me</a>
<div class="outer">
  <div class="text">outer</div>
  <div class="inner">
    <div class="text">inner</div>
  </div>
</div>
<div class="inner-expectation"></div>
&#13;
&#13;
&#13;

问题是当悬停结束时,效果会中断。但这无法完美解决。

反转时,外部的比例为(1+f(t))/2,内部2-g(t)的比例(相对于外部)。

从绝对意义上讲,内心的规模将是

(1+f(t))/2 * (2-g(t)) = 1 - g(t)/2  + f(t) - f(t)g(t)/2

我们希望这是1。然后,f(t) = g(t) / ( 2-g(t) )

但我们已经有f(t) = 2 g(t) / (1+g(t))

g(t) / ( 2-g(t) ) = 2 g(t) / (1+g(t))   =>   g(t) = 1

g(0)必须是0。矛盾。你无法在两个方向上取得完美的成绩。

如果您愿意使用JS,当鼠标进入或离开目标元素时,您可以交换外部和内部的计时功能。

答案 1 :(得分:4)

编辑:继续为bezier曲线做一个示例代码。

http://codepen.io/anon/pen/jAYOBO&lt; - (旧)

现在使用曲线转换回正常元素状态:

http://codepen.io/anon/pen/oLpLLG&lt; - (新)

您面临的问题是这些操作的相对性。你必须为游戏中的过渡提供不同的值。您对变换有正确的数学逻辑,但是,您修改这些特征的过渡不会被调整为保持相同的动画具有各自不同的值 - 过渡值是相同的。

这意味着即使您在转换的两个对象之间有完美的2:1比例,它们的变化率在过程的不同步骤中本质上是不同的 - 无论其目的地/最终结果如何< / strong>即可。如果希望它们在外观上均衡,则需要调整转换设置。

仍然困惑?换句话说......

假设您在不相互影响的单独容器中有2个div框。这里有一些CSS来传达它们的相关属性:

div.a{
width:100px;
height:100px;
}

div.b{
width:200px;
height:200px;
}

我们可以对这些完全相同的过渡:线性,10s,并用scale()将它们各自的大小加倍。 (div.a的高度/宽度为200px,div.b的高度/宽度为400px)

现在,虽然它似乎与你的情况无关,但很明显这两个不会以同样的速度“增长” - (不同的开始,不同的目的地[不会同样否定初始的起始差异],持续时间相同) - 这是你遇到的同一个问题。

要解决问题并使动画以您期望的方式运行,您必须修改转换的计时功能。

为了证明我所描述的现象确实实际上正在发生,我已经将你的一个转换元素的转换类型改为一个简化和分叉的转换元素。下面的codepen链接。玩它,你会得到我在说什么。如果您需要更多信息,请评论我的答案!

http://codepen.io/anon/pen/qNVgBB

有用的链接:http://cubic-bezier.com/

进一步阅读:Quadratic Bezier Curve: Calculate Point

(另外,我确信数学堆栈交换的人会为你咀嚼这些东西。我几乎肯定他们可以给你一个更清晰的曲线如何分解工作。) (呃,现在这很混乱。我会清理它并稍后重新格式化)

答案 2 :(得分:0)

scaleY()会影响parentchild元素大小调整(例如height)。

您正在以两种方式缩放child元素height同时增加和减少。您看到的是完全预期的行为给定值和您为元素设置的属性。

假设以下内容:

  • {height} parentchild都是100px
  • scaleY parent的金额为0.5 (这也影响childchild为{{ 1}}。
  • 2时间为transition

1000ms

  • 500ms应缩放为parent0.75
  • 100px * 0.75 = 75px height应缩放为child1.5

75px * 1.5 = 112.5px height

  • 1000ms应缩放为parent0.5
  • 100px * 0.5 = 50px height应缩放为child)(2

这就是为什么你会遇到&#34;增长然后收缩&#34; 的行为。

我不会花时间摆弄一些立方贝塞尔值,而是责备你的元素结构和设计。