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 :
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!
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)?
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:
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
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)
By way of a revision of my initial answer which produced an output rather than an explanation, I would postulate* that the effect is seen because you are surmising a negative skew can be used to offset a position on the positive skew curve, when in fact- at minus values you are operating on the negative skew curve.
This would first require that the measure of skew was singular and occurring on the same curve (see normal curve below), with positive and negative values allowing to shift along the curve.
However, the curve for negative and positive skews are inversly tailed.
Zero skew is the only value which operates the same on both. As such, if you have an element, apply a skew of 20 degrees to it, then apply a skew of minus 20 you will actually have a skew (positive or negative) of zero, so using a negative offset appears to work..
However, if you then apply additional negative skew, you will have a negatively skewed element, the curve for which is different and not equal to the inverse equivalent position on the positive skew curve.
20deg = Original element, 20deg on positive skew curve
20deg - 20deg = 0, same for positive and negative skew curve
-40deg = taking the elements current 20deg skew, minus 40 deg = 20deg on negative skew curve - NOT an equivalent 'opposite' point on the positive skew curve
When using psuedos, the skew works because you arent offsetting a positively skewed value by a newgatively skewed amount.
* Im no mathematician, so afraid I can only claim this as conjecture
I will just address to the main issue, as to why it happens, instead of trying to provide alternatives
Since your math appears to be exact, we have to search for what is not exact, which is the platform itself...
MDN's article on transform states that it is not a stable technology:
This is an experimental technology
Because this technology's specification has not stabilized, check the
(emphasis mine)
Consider the following:
When you skew the main div, it requires a huge amount of browser render calculations to show in a 2D environment what it would look like considering both 3 axis... The pseudo element suffer with those calculations, as you can see if you further it a little left from the edge where you've put it:
See that I just moved to the left, and that caused it to go down a little, according to the Y skewing applied to the main div. Now, add to that another huge amount of calculations when you re-skew the pseudo element... The browser will just fail to provide an accurate render of what the 3D space would look like in a 2D environment...
Related
I am trying to render beautiful pages transitions in my react application. I chose simple fade-in/fade-out transitions, and they work perfectly for random pages. But it happens that some pages are quite identical (just a text change), and in that case the transition is not so good (see code-pen bellow for a concrete example).
The way I understand mathematics, if I have two layers, let's say A and B, a linear fade-out of A starting above a similar linear fade-in of B should give constant pixels colors for pixels of the exact same color in both layers, isn't it? But as you can see in that codepen, it's not the case (i was hoping to have no visual effect as the two layers have the exact same color), and I don't understand why. Is there a way to obtain the desired result (for a given pixel, color B replace color A if they are different, but stay still if they are the same)?
https://codepen.io/st-phane-smirnow/pen/dyJaBPG
And here is the corresponding code - HTML:
<div class="a1">a1 div</div>
<div class="a2 hidden">a2 div</div>
<button>Switch divs<button>
CSS:
.a1, .a2 {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: red;
transition: all .5s linear;
}
.hidden { opacity: 0; }
button {
position: absolute;
top: 10px;
left: 10px;
}
JS:
window.addEventListener("load", () => {
document.querySelector("button").addEventListener("click", () => {
document
.querySelectorAll("div")
.forEach(d => d.classList.toggle("hidden"));
});
});
EDIT: I partially solved my problem by disabling the transparency of the underlying layer. That way, the application background, whatever it is, is hidden by the second layer (opacity always to 1), and the foremost layer just fade-in the underlaying layer. I don't know if, in a perfect world, that result is really different of what I would have got of a truly functional cross-fade, but at least it give a good result at screen.
It's because during the transition, they are both transparent so you're seeing the white background through them.
Here's an interesting post that shows some formulas that might help to why the resulting color isn't rgb(255,0,0) all the way through. Basically, some of the green and blue channel are being introduced.
It's reasonable to think that a 90% red + a 10% red would be a 100% red, but actually each layer is letting a little bit of 'white light' through. Here's how:
According to the post, the general formula for a 2 layer image is:
Y = p*T+(1-p)*B where...
p is the opacity 0...1 of the top layer,
T = rgb number of top layer color,
B is the rgb number of fully opaque bottom layer.
Y is the rgb number of the equivalent fully opaque color.
So, say you have rgba(255, 0, 0, 0.9) on a white background. The resulting color is:
r = 0.9 * 255 + 0.1 * 255 = 255
g = 0.9 * 0 + 0.1 * 255 = 25.5
b = 0.9 * 0 + 0.1 * 255 = 25.5
Now let's add a rgba(255, 0, 0, 0.1) on top of that result:
r = 0.1 * 255 + 0.9 * 255 = 255
g = 0.1 * 0 + 0.9 * 25.5 = 22.9
b = 0.1 * 0 + 0.9 * 25.5 = 22.9
The extra green and blue channels are moving the color towards white.
After combing through the SVG specification, and guides such as this and this, I am still struggling to understand exactly how chaining transforms work.
Selected Relevant Quotes
When you apply the transform attribute to an SVG element, that element
gets a "copy" of the current user coordinate system in use.
And:
When transformations are chained, the most important thing to be aware
of is that, just like with HTML element transformations, each
transformation is applied to the coordinate system after that system
is transformed by the previous transformations.
And:
For example, if you’re going to apply a rotation to an element,
followed by a translation, the translation happens according to the
new coordinate system, not the inital non-rotated one.
And:
The sequence of transformations matter. The sequence the
transformation functions are specified inside the transform attribute
is the sequence they are applied to the shape.
Code
The first rectangle's current coordinate system is scaled, then rotated (note the order). The second rectangle's current coordinate system is rotated, then scaled.
svg {
border: 1px solid green;
}
<svg xmlns="http://www.w3.org/2000/svg">
<style>
rect#s1 {
fill: red;
transform: scale(2, 1) rotate(10deg);
}
</style>
<rect id="s1" x="" y="" width="100" height="100" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg">
<style>
rect#s2 {
fill: blue;
transform: rotate(10deg) scale(2, 1);
}
</style>
<rect id="s2" x="" y="" width="100" height="100" />
</svg>
Question
We know that when we chain transforms, a copy is made of the current coordinate system in use for that element, then the transforms are applied in the order they are specified.
When we have a user coordinate system that is already scaled, and we apply a rotate to it, the rectangle is (as seen) effectively skewed (notice the changed angles). This does not happen if we do the two transforms the other way around (rotate, then scale).
Expert help on exactly how the scaled current coordinate system is rotated, would be deeply appreciated. I am trying to understand, from a technical (inner workings) angle, exactly why the skewing happens in the first rectangle.
Thank you.
To illustrate how it works let's consider an animation to show how the scaling effect change the rotation.
.red {
width:80px;
height:20px;
background:red;
margin:80px;
transform-origin:left center;
animation: rotate 2s linear infinite;
}
#keyframes rotate {
from{transform:rotate(0)}
to{transform:rotate(360deg)}
}
<div class="container">
<div class="red">
</div>
</div>
As you can see above, the rotation is creating a perfect circle shape.
Now let's scale the container and see the difference:
.red {
width:80px;
height:20px;
background:red;
margin:80px;
transform-origin:left center;
animation: rotate 5s linear infinite;
}
#keyframes rotate {
from{transform:rotate(0)}
to{transform:rotate(360deg)}
}
.container {
display:inline-block;
transform:scale(3,1);
transform-origin:left center;
}
<div class="container">
<div class="red">
</div>
</div>
Notice how we no more have a circle but it's an ellipse now. It's like we took the circle and we stertch it which is creating the skew effect inside our rectangle.
If we do the opposite effect and we start by having a scale effect and then we apply a rotation we won't have any skewing.
.red {
width:80px;
height:20px;
background:red;
margin:80px;
animation: rotate 2s linear infinite;
}
#keyframes rotate {
from{transform:scale(1,1)}
to{transform:scale(3,1)}
}
.container {
display:inline-block;
transform:rotate(30deg);
transform-origin:left center;
}
<div class="container">
<div class="red">
</div>
</div>
To explain it differently: Applying a rotation will keep the same ratio between both X and Y axis so you won't see any bad effect when doing scale later but scaling only one axis will break the ratio thus our shape we look bad when we try to apply a rotation.
You can check this link if you want more details about how transform are chained and how the matrix is caclulated: https://www.w3.org/TR/css-transforms-1/#transform-rendering. It's about HTML element but as said in the SVG specification it's the same.
Here is the relevant parts:
Transformations are cumulative. That is, elements establish their local coordinate system within the coordinate system of their parent.
From the perspective of the user, an element effectively accumulates all the transform properties of its ancestors as well as any local transform applied to it
Let's do some math in order to see the difference between both transformations. Let's consider matrix multiplication and since we are dealing with a 2D linear transformation we will do this on ℝ² for simplicity1.
For scale(2, 1) rotate(10deg) we will have
|2 0| |cos(10deg) -sin(10deg)| |2*cos(10deg) -2*sin(10deg) |
|0 1| x |sin(10deg) cos(10deg) | = |1*sin(10deg) 1*cos(10deg) |
Now if we apply this matrix to an (Xi,Yi) we will obtain (Xf,Yf) like below:
Xf = 2* (Xi*cos(10deg) - Yi*sin(10deg))
Yf = Xi*sin(10deg) + Yi*cos(10deg)
Note how the Xf is having an extra multiplier which is the culprit of creating the skew effect. It's like we changed the behavior or Xf and kept the Yf
Now let's consider rotate(10deg) scale(2, 1):
|cos(10deg) -sin(10deg)| |2 0| |2*cos(10deg) -1*sin(10deg) |
|sin(10deg) cos(10deg) | x |0 1| = |2*sin(10deg) 1*cos(10deg) |
And then we will have
Xf = 2*Xi*cos(10deg) - Yi*sin(10deg)
Yf = 2*Xi*sin(10deg) + Yi*cos(10deg)
We can consider the 2*Xi as an Xt and we can say that we rotated the (Xt,Yi) element and this element was initially scaled considering the X-axis.
1CSS uses also affine transformation (like translate) so using ℝ² (Cartesian coordinates) isn't enough to perform our calculation so we need to consider ℝℙ² (Homogeneous coordinates). Our previous calculation will be:
|2 0 0| |cos(10deg) -sin(10deg) 0| |2*cos(10deg) -2*sin(10deg) 0|
|0 1 0| x |sin(10deg) cos(10deg) 0| = |1*sin(10deg) 1*cos(10deg) 0|
|0 0 1| |0 0 1| |0 0 1|
Nothing will change in this case because the affine part is null but if we have a translation combined with another transform (ex: scale(2, 1) translate(10px,20px)) we will have the following:
|2 0 0| |1 0 10px| |2 0 20px|
|0 1 0| x |0 1 20px| = |0 1 20px|
|0 0 1| |0 0 1 | |0 0 1 |
And
Xf = 2*Xi + 20px;
Yf = Yi + 20px;
1 = 1 (to complete the multiplication)
The way Temani Afif explained it follows the coordinate systems that every transformation spans. You start with the viewport, and each consecutive coordinate system is derived and sits somewhere different on the canvas. These coordinate systems might turn out not be cartesian (a "stretched universe"). They are constructed in the DOM tree from the outside in, and when chained in an attribute, from left to right.
But you can imagine the same transformation also in the opposite direction, from the inside out: first you draw a rectangle in its cartesian userspace coordinate system, and than you transform it by a chain of scales, rotations and so on, until when drawing it in the viewport coordinate system, it is distorted to something else.
But if you look at it this the second way, the chained transformations in an attribute need to be processed right to left: transform: scale(2, 1) rotate(10deg) means take a rectangle, first rotate it by 10deg, and then scale the rotated rectangle in the horizontal direction.
In short, these two are equivalent:
If you draw a grafic in a transformed coordinate system, construct the coordinate system by applying transforms to these coordinate systems left-to-right.
If you draw a transformed grafic in the original coordinate system, construct the grafic by applying transforms to the grafic right-to-left.
After combing through the SVG specification, and guides such as this and this, I am still struggling to understand exactly how chaining transforms work.
Selected Relevant Quotes
When you apply the transform attribute to an SVG element, that element
gets a "copy" of the current user coordinate system in use.
And:
When transformations are chained, the most important thing to be aware
of is that, just like with HTML element transformations, each
transformation is applied to the coordinate system after that system
is transformed by the previous transformations.
And:
For example, if you’re going to apply a rotation to an element,
followed by a translation, the translation happens according to the
new coordinate system, not the inital non-rotated one.
And:
The sequence of transformations matter. The sequence the
transformation functions are specified inside the transform attribute
is the sequence they are applied to the shape.
Code
The first rectangle's current coordinate system is scaled, then rotated (note the order). The second rectangle's current coordinate system is rotated, then scaled.
svg {
border: 1px solid green;
}
<svg xmlns="http://www.w3.org/2000/svg">
<style>
rect#s1 {
fill: red;
transform: scale(2, 1) rotate(10deg);
}
</style>
<rect id="s1" x="" y="" width="100" height="100" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg">
<style>
rect#s2 {
fill: blue;
transform: rotate(10deg) scale(2, 1);
}
</style>
<rect id="s2" x="" y="" width="100" height="100" />
</svg>
Question
We know that when we chain transforms, a copy is made of the current coordinate system in use for that element, then the transforms are applied in the order they are specified.
When we have a user coordinate system that is already scaled, and we apply a rotate to it, the rectangle is (as seen) effectively skewed (notice the changed angles). This does not happen if we do the two transforms the other way around (rotate, then scale).
Expert help on exactly how the scaled current coordinate system is rotated, would be deeply appreciated. I am trying to understand, from a technical (inner workings) angle, exactly why the skewing happens in the first rectangle.
Thank you.
To illustrate how it works let's consider an animation to show how the scaling effect change the rotation.
.red {
width:80px;
height:20px;
background:red;
margin:80px;
transform-origin:left center;
animation: rotate 2s linear infinite;
}
#keyframes rotate {
from{transform:rotate(0)}
to{transform:rotate(360deg)}
}
<div class="container">
<div class="red">
</div>
</div>
As you can see above, the rotation is creating a perfect circle shape.
Now let's scale the container and see the difference:
.red {
width:80px;
height:20px;
background:red;
margin:80px;
transform-origin:left center;
animation: rotate 5s linear infinite;
}
#keyframes rotate {
from{transform:rotate(0)}
to{transform:rotate(360deg)}
}
.container {
display:inline-block;
transform:scale(3,1);
transform-origin:left center;
}
<div class="container">
<div class="red">
</div>
</div>
Notice how we no more have a circle but it's an ellipse now. It's like we took the circle and we stertch it which is creating the skew effect inside our rectangle.
If we do the opposite effect and we start by having a scale effect and then we apply a rotation we won't have any skewing.
.red {
width:80px;
height:20px;
background:red;
margin:80px;
animation: rotate 2s linear infinite;
}
#keyframes rotate {
from{transform:scale(1,1)}
to{transform:scale(3,1)}
}
.container {
display:inline-block;
transform:rotate(30deg);
transform-origin:left center;
}
<div class="container">
<div class="red">
</div>
</div>
To explain it differently: Applying a rotation will keep the same ratio between both X and Y axis so you won't see any bad effect when doing scale later but scaling only one axis will break the ratio thus our shape we look bad when we try to apply a rotation.
You can check this link if you want more details about how transform are chained and how the matrix is caclulated: https://www.w3.org/TR/css-transforms-1/#transform-rendering. It's about HTML element but as said in the SVG specification it's the same.
Here is the relevant parts:
Transformations are cumulative. That is, elements establish their local coordinate system within the coordinate system of their parent.
From the perspective of the user, an element effectively accumulates all the transform properties of its ancestors as well as any local transform applied to it
Let's do some math in order to see the difference between both transformations. Let's consider matrix multiplication and since we are dealing with a 2D linear transformation we will do this on ℝ² for simplicity1.
For scale(2, 1) rotate(10deg) we will have
|2 0| |cos(10deg) -sin(10deg)| |2*cos(10deg) -2*sin(10deg) |
|0 1| x |sin(10deg) cos(10deg) | = |1*sin(10deg) 1*cos(10deg) |
Now if we apply this matrix to an (Xi,Yi) we will obtain (Xf,Yf) like below:
Xf = 2* (Xi*cos(10deg) - Yi*sin(10deg))
Yf = Xi*sin(10deg) + Yi*cos(10deg)
Note how the Xf is having an extra multiplier which is the culprit of creating the skew effect. It's like we changed the behavior or Xf and kept the Yf
Now let's consider rotate(10deg) scale(2, 1):
|cos(10deg) -sin(10deg)| |2 0| |2*cos(10deg) -1*sin(10deg) |
|sin(10deg) cos(10deg) | x |0 1| = |2*sin(10deg) 1*cos(10deg) |
And then we will have
Xf = 2*Xi*cos(10deg) - Yi*sin(10deg)
Yf = 2*Xi*sin(10deg) + Yi*cos(10deg)
We can consider the 2*Xi as an Xt and we can say that we rotated the (Xt,Yi) element and this element was initially scaled considering the X-axis.
1CSS uses also affine transformation (like translate) so using ℝ² (Cartesian coordinates) isn't enough to perform our calculation so we need to consider ℝℙ² (Homogeneous coordinates). Our previous calculation will be:
|2 0 0| |cos(10deg) -sin(10deg) 0| |2*cos(10deg) -2*sin(10deg) 0|
|0 1 0| x |sin(10deg) cos(10deg) 0| = |1*sin(10deg) 1*cos(10deg) 0|
|0 0 1| |0 0 1| |0 0 1|
Nothing will change in this case because the affine part is null but if we have a translation combined with another transform (ex: scale(2, 1) translate(10px,20px)) we will have the following:
|2 0 0| |1 0 10px| |2 0 20px|
|0 1 0| x |0 1 20px| = |0 1 20px|
|0 0 1| |0 0 1 | |0 0 1 |
And
Xf = 2*Xi + 20px;
Yf = Yi + 20px;
1 = 1 (to complete the multiplication)
The way Temani Afif explained it follows the coordinate systems that every transformation spans. You start with the viewport, and each consecutive coordinate system is derived and sits somewhere different on the canvas. These coordinate systems might turn out not be cartesian (a "stretched universe"). They are constructed in the DOM tree from the outside in, and when chained in an attribute, from left to right.
But you can imagine the same transformation also in the opposite direction, from the inside out: first you draw a rectangle in its cartesian userspace coordinate system, and than you transform it by a chain of scales, rotations and so on, until when drawing it in the viewport coordinate system, it is distorted to something else.
But if you look at it this the second way, the chained transformations in an attribute need to be processed right to left: transform: scale(2, 1) rotate(10deg) means take a rectangle, first rotate it by 10deg, and then scale the rotated rectangle in the horizontal direction.
In short, these two are equivalent:
If you draw a grafic in a transformed coordinate system, construct the coordinate system by applying transforms to these coordinate systems left-to-right.
If you draw a transformed grafic in the original coordinate system, construct the grafic by applying transforms to the grafic right-to-left.
This question already has answers here:
Using percentage values with background-position on a linear-gradient
(2 answers)
Closed 3 years ago.
I don't know if it's the late hour or if I'm just being stupid, but I can't figure this out.
What I'm trying to do is position a background image just outside the element it belongs to using %. The reason I want to do is is so that I can later animate the background-position from this % to 50% having it "slide in".
If I could use pixels it's easy enough to set the background-position to [width-of-element]px 0 but as I want the element's final position to be 50% 0 I can't start with a pixel value. (I'm using the jQuery Background Position plugin btw http://keith-wood.name/backgroundPos.html).
So, my question is, knowing the width of the element and the width of the background image - how can I calculate which %:age is needed to position the image just outside the edge of the element?
Obviously setting the background position to "0 0" makes it render at the top left, "50% 0" makes it centered and "100% 0" positions it from the right edge. If I go above 100% it starts to move away from the right edge, and depending on the width of the image (and I guess, the element) any value from roughly 200 and up is needed to completely shove the background image outside the edge of the element.
If I go the other way around, from 0 and downward the image moves off to the right, again the % needed to hide it varies but is not the same as the positive % needed to push it off the other edge.
Again, maybe I'm just tired but I'm stuck here.
http://jsfiddle.net/cTeEA/
Edit: Another curious thing I noticed is that if the image is smaller than the containing element, increasing its background-position-x above 100% doesn't make it move away from the right instead it makes it move to the right. Adjust the 101% on this updated fiddle and compare with the old fiddle to see what I mean: http://jsfiddle.net/cTeEA/1/
Edit: Ok percentages seemed out of the question, or at least ten times harder than simply using pixels. Here's how I solved it (more or less):
var dir = 'left'; // || 'right' (where to slide in the image from)
var winWidth = $(document).width();
var imgWidth = $('img[src="src-of-already-added-and-loaded-img.png"]').width();
var posOutside = dir == 'right' ? '-' + imgWidth + 'px' : winWidth + 'px';
var posCenter = (imgWidth > winWidth) ? -((imgWidth - winWidth) / 2) : ((winWidth - imgWidth) / 2);
Then I just animated the background-position from posOutside to posCenter.
Thanks to those who helped in the comments as well.
Background position with percentage values is not easy.
You can see an explanation of the math involved here
In your case, the short answer is:
The background size is greater or smaller than the div by a factor of f. Then your percentage is 100 / (1 - f).
That means that:
The backgound size is the same than the div. You are out of luck, it's not posible.
The background is bigger. Say div=100 background=400, then f = 4 and the formula gives -33%. (first example in demo)
The background is narrower. Say div=400 background=100, f=0.25 and the formula gives 133% (second example in the demo)
demo
Notice that in the demo the percentages are a little bit offset to show that the background is really there
css:
div.foo {
width: 100px;
background-size: 400px 100px;
background: red url(http://placekitten.com/400/100) no-repeat 50% 0;
height: 100px;
background-position: -32% 0; /* Disappear to the left */
}
div.foo2 {
width: 400px;
background-size: 100px 100px;
background: red url(http://placekitten.com/100/100) no-repeat 50% 0;
height: 100px;
background-position: 132% 0; /* Disappear to the left */
}
I am using CSS transitions like this:
div
{
-webkit-transform: rotate(0deg);
-webkit-transition: -webkit-transform 2s;
}
div:hover
{
-webkit-transform: rotate(720deg);
}
This effectively makes the div rotate 2 times for 2 seconds. Now I want to use the matrix so that I can rotate and scale the image; however the matrix does not use degrees but cos(a) and sin(a) and as we all know cos(0) = cos(360) = cos(720) etc. So using the matrix I am unable to rotate the image more than 359deg.
So I decided to be clever and with JavaScript I took the matrix from a rotated element (720deg) and it looks like this:
-webkit-transform: matrix(1, -0.0000000000000004898587196589413, 0.0000000000000004898587196589413, 1, 0, 0);
However using this matrix I am not able to rotate the element - I will later calculate the size and apply that too.
So the question is - how do I rotate an element more than 359deg using css 3 matrix transform?
Matrices in CSS 3 define
a mathematical mapping from one coordinate system into another
(W3C reference),
which implies that 720deg is exactly equivalent to 360deg as you pointed out. So you will not be able to do this directly with a matrix.
However, this syntax should work for your need :
div:hover {
transform: scale(1.5,1.5) rotate(720deg);
transition: transform 3s;
}