Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unskewed child not aligning

Note: This question is about a problem with output, and not about creation of any shape.


I recently created a shape :

.prog {
    position: relative;
    top: 20px;
    width: 150px;
    height: 120px;
    background: green;
    display: inline-block;
    transform: skewY(20deg);
    transform-origin: 0% 100%;
    transition: 0.8s ease;
}
.prog:before {
    content: "";
    position: absolute;
    left: 150px;
    width: 150px;
    height: 120px;
    background: red;
    transform: skewY(-40deg);
    transform-origin: 0% 100%;
    transition: 0.8s ease;
}
<div class="prog "></div>

In the above snippet, the green shape is the .prog element, and is skewed. The red shape is :before pseudoelement of the first element.

I skewed .prog (skewY) to 20deg. Now, I needed :before to be -20deg. For this, I first had to unskew it. Then skew it further 20deg.
So final skewY value will be -40deg. I applied this, and appropriate transform-origins.

But the problem is that the top points of both the shapes aren't aligning. They should, but they aren't. Here's an image showing the problem :

unskewed child not aligning

The black lines are just for reference.

Now even more!

I skewed -20 -20 instead of -40 :

transform: skewY(-20deg) skewY(-20deg); <-- This works!
transform: skewY(-40deg); <---------------- This doesn't!

like image 564
The Pragmatick Avatar asked Feb 03 '15 14:02

The Pragmatick


2 Answers

The behaviour of the "unskewed" child is normal, it is the way skew works. In order to understand this, I am going to simplify the question to :

why isn't skewX(40deg) the same as skewX(20deg) skewX(20deg)?

Difference between skewX(40deg) and skewX(20deg) skewX(20deg)

div {
    width: 100px; height: 100px;
    position:absolute;
    top:20px; left:20px;
    transform-origin: 0 0;
}
.d1 {
    transform: skewX(40deg);
    background: red;
    opacity:0.7;
}
.d2 {
    transform: skewX(20deg) skewX(20deg);
    background: blue;
    opacity:0.7;
}
/** FOR THE DEMO **/
body {background: url('http://i.stack.imgur.com/GySvQ.png');background-size: 10px;}
.m {text-align:right;padding-top:105px;}
.m1{width:83px;color:red;border-right:1px solid red;}
.m2 {width:72px;color:blue;border-right:1px solid blue;}
p{margin:0 0 5px 150px;color:red;}
.b{color:blue;}
<div class="d1"></div>
<div class="d2"></div>
<div class="m m1">x = 83</div>
<div class="m m2"><br/>x = 72</div>
<p class="r">skewX(40deg)</p>
<p class="b">skewX(20deg) skewX(20deg)</p>

Note: for the sake of explanation I will be using a 100*100 square div and the transform origin is set on the top left corner of this div. Like in the above code snippet.


To understand the difference between the two transformations, we need to explore the way the CSS skew() function works. The specs say :

A 2D skew transformation along the X axis with the parameter alpha is equivalent to the matrix: skewX() matrix

So this means we can calculate the coordinates of each point of a 2D X skewed element like this :

| 1 tan(α) | . | x |
| 0   1    |   | y |
  • α is the X skewed angle
  • x/y the coordinates of the point before transformation

For skewX(40deg)

α = tan(40deg) ~= 0.83

| 1  0.83 | . | 0   |   | 83  |
| 0  1    |   | 100 | = | 100 |

The new coordinates are x = 83 as seen in the code snippet example.


For skewX(20deg) skewX(20deg)

α = tan(20deg) ~= 0.36

first skew :

| 1  0.36 | . | 0   |   | 36  |
| 0  1    |   | 100 | = | 100 |

Second skew :

| 1  0.36 | . | 36  |   | 72  |
| 0  1    |   | 100 | = | 100 |

The new coordinates are x = 72 as seen in the code snippet.


Conclusion

Both transformations don't give the same result. So skewY(20deg) skewY(-40deg) isn't the same transformation as skewY(-20deg) and the two top corners of the red and green elements can't align as :

tan(20deg) != tan(40deg)/2 

References :

  • The CSS3 matrix() Transform for the Mathematically Challenged
  • CSS transform skew: math unveiled
  • CSS Transforms Module Level 1
like image 180
web-tiki Avatar answered Oct 14 '22 08:10

web-tiki


skew introduces a vertical offset equal to the tangent of the angle. So, skew(20deg) introduces an offset of tan(20deg).

For your example to work, it should be that

tan(-20deg) = tan(20deg) + tan( -2 * 20deg)

or

tan (2 * x) = 2 * tan (x)

but this is not true, tangent and sum are not asociative

the required skew to reverse it is

result = - atan ( 2 * tan (x))

that, for x = 20, gives a result of

36,052388732387908475278040193987

(aproximately)

like image 26
vals Avatar answered Oct 14 '22 07:10

vals