Nested css scale transformations don't cancel each other out

I have an image that changes its height based on the view / detail state. This should be a background image with background-size: cover to ensure that the container is closed at any time.

Since the transition must be completed, I see no other way than using transform: scaleY(0.5) in the wrapper element and the corresponding transform: scaleY(2) in the inner element, which cancels the scale effect.

At the beginning and at the end, the math is correct. However, the transition does not look right. I prepared a small violin to illustrate what is going wrong:

Codepen - Fiddle

As you can see, the transitions, although linear, do not exactly cancel each other out. I believe that there is a basic mathematical problem, but I can not find a solution for it.

+6
source share
3 answers

edit: went ahead and made an example codepen for a Bezier curve.

http://codepen.io/anon/pen/jAYOBO <- (old)

Now with a curve to go to the normal state of the element:

http://codepen.io/anon/pen/oLpLLG <- (new)

The problem you are facing is related to the relativity of these operations. You will need to give different values ​​for the transitions in the game. You have the correct mathematical logic regarding the transformations, however, the transitions that you change, change these characteristics, are not adjusted to maintain the same animation with their own, respectively, different values ​​- the transition values ​​are the same.

This means that even if you have an ideal 2: 1 scale between two transferred objects, the speed of their change differs differently at different stages of the process - regardless of their final / final result . You need to adjust the transition parameters if you want them to be balanced in appearance.

Still confused? In other words...

Suppose you have 2 div boxes in separate containers that do not affect each other. Here are some CSS to pass on their respective properties:

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

We could pass them the same: linear, 10 s and doubling their respective sizes using scale() . ( div.a will be 200px in height / width, and div.b will be 400px in height / width)

Now, although it may seem unrelated to your circumstances and it is obvious that these 2 will not β€œgrow” at the same speed - (different starts, different destinations [which do not equally deny the initial differences of the beginning] with the same duration) - this is the very problem you are facing.

To fix the problem and make the animation behave as you expect, you will have to change the synchronization functions of your transition.

To demonstrate that the phenomenon that I am describing is really happening, I went ahead and changed the type of transition for one of the transforming elements to one, which facilitates and forks it through the codepen link below. Play with him and you will get what I am talking about. If you need more information, comment on my answer!

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

Useful link: http://cubic-bezier.com/

Further reading: Bezier quadratic curve: calculate point

(In addition, I’m sure that people involved in math exchange would like to chew on this material for you. I’m pretty sure that they can give you a much clearer picture of how curves work.) (Wow, this is dirty, as of now, I will clear this and reformat it later)

+4
source

The outer element is interpolated between scaleY(1) and scaleY(0.5) .

At time t transformation will be scaleY(1-t/2)

  t = 0 tt = 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 β”‚ β”” β”˜ β”” β”˜ β”” β”˜ 

The inner element is interpolated between scaleY(1) and scaleY(2) .

At time t transformation will be scaleY(1+t)

  t = 0 tt = 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 β”‚ β”” β”˜ β”” β”˜ β”” β”˜ 

However, this is relatively external. In absolute terms, matrices are multiplied:

  t = 0 tt = 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 β”‚ β”” β”˜ β”” β”˜ β”” β”˜ 

Then yes, the start and end points correspond to the identity matrix.

But between you there is a scaleY(1+t/2-tΒ²/2) parabola scaleY(1+t/2-tΒ²/2) .

enter image description here

It is possible to achieve the desired effect using Bezier curves.

Let f(t) and g(t) be the temporary functions of .outer and .inner respectively.

By definition, f(0) = g(0) = 0 and f(1) = g(1) = 1 .

The external value scale will be indicated by

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

We want this to be 1 , so

 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 

That is, the initial slope of the outer should be double than the inner, and vice versa for the end slopes.

By choosing f(t) = t (linear) and g , the Bezier curve given by (.3, 0.15), (.7, .4) seems to give good results. Note g'(0) = 2 = 2 f'(0) and 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> 

The problem is when the guidance ends, then the effect breaks. But it is impossible to solve.

When reversing, the scale of the external value will be (1+f(t))/2 , and the scale of the internal 2-g(t) (relative to the external).

In absolute terms, the scale of the internal will be

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

And we want this to be 1 . Then f(t) = g(t) / ( 2-g(t) ) .

But we already had f(t) = 2 g(t) / (1+g(t)) .

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

But g(0) must be 0 . Contradiction. You cannot achieve perfect results in both directions.

If you want to use JS, you can change the temporary functions of the external and internal when the mouse enters or leaves the target element.

+4
source

scaleY() affects the size of the parent and child elements (e.g. height ).

You scale the child height element in two ways, while increasing and decreasing it. What you see is a fully expected behavior, given the values ​​and properties that you set for the elements.

Assume the following:

  • parent and child are 100px in height.
  • scaleY sum for parent is 0.5 (which also affects child ), and child is 2 .
  • transition time is 1000ms .

At 500ms :

  • parent should be scaled to 0.75 ( 100px * 0.75 = 75px height )
  • child should be scaled to 1.5 ( 75px * 1.5 = 112.5px height )

In 1000ms :

  • parent should be scaled to 0.5 ( 100px * 0.5 = 50px height )
  • child should be scaled to 2 ) ( 50px * 2 = 100px height )

This is why you experience "grow and then shrink."

I would not waste time on some cubic bezier values, rather, a rebuke in the structuring and design of the element.

0
source

All Articles