Simulating transform-origin using translate - css

I want to simulate the properties of transform-origin using transform: translate in CSS.
According to MDN, this is very possible:
This property is applied by first translating the element by the negated value of the property, then applying the element's transform, then translating by the property value.
However, when I try, I get incorrect results. These two rectangles are clearly not the same:
.origin {
transform-origin: 100px 100px;
transform: translate(100px, 0px) scale(2) rotate(45deg);
}
.translate {
transform: translate(-100px, -100px) translate(100px, 0px) scale(2) rotate(45deg) translate(100px, 100px);
}
.box {
background-color: red;
width: 100px;
height: 100px;
}
.container {
float: left;
margin: 100px;
width: 250px;
height: 250px;
background-color: rgba(0, 0, 0, 0.1);
}
<div class="container">
<div class="box origin">
</div>
</div>
<div class="container">
<div class="box translate">
</div>
</div>
I have tried looking for the answer without luck for quite some time now, and in my mind it should be relatively simple, I just can't figure it out.

You are almost good but you have two errors. You need to invert the translations and you need to change the transform-origin of the second one.
If you check the documentation, you will see that the reference used to translate the origin is the top left corner of the element and the default value of transform origin is center. So we need to have the same reference for both.
.origin {
transform-origin: 50px 50px;
transform: rotate(45deg) scale(2);
}
.translate {
transform-origin:0 0;
transform:translate(50px, 50px) rotate(45deg) scale(2) translate(-50px, -50px);
}
.box {
background-color: red;
width: 50px;
height: 50px;
}
.container {
display: inline-block;
margin: 30px;
width: 150px;
height: 150px;
background-color: rgba(0,0,0,0.1);
}
<div class="container">
<div class="box origin">
</div>
</div>
<div class="container">
<div class="box translate">
</div>
</div>
Here is from the specification:
The transformation matrix is computed from the transform and
transform-origin properties as follows:
Start with the identity matrix.
Translate by the computed X and Y of transform-origin
Multiply by each of the transform functions in transform property from
left to right
Translate by the negated computed X and Y values of transform-origin
You need to pay attention to the wording! You may find that the MDN is contradictory with the specification BUT it's not the case simply because there is a difference between translating the element (like described in the MDN) and translating the origin of the element or the local coordinate (like described in the specification).
For example, translating the element by -50px is equivalent to translating its local coordinate (origin) by +50px.
You need to also pay attention to the "Multiply from left to right" as it may create confusion. If we refer to the same specification in the Example 3 we have:
div {
height: 100px; width: 100px;
transform: translate(80px, 80px) scale(1.5, 1.5) rotate(45deg);
}
This transformation translates the local coordinate system by 80
pixels in both the X and Y directions, then applies a 150% scale, then
a 45° clockwise rotation about the Z axis. The impact on the
rendering of the element can be intepreted as an application of these
transforms in reverse order: the elements is rotated, then scaled,
then translated.
So multiplying from left to right doesn't mean applying from left to right which somehow explain the need of inverting the translation you applied to simulate the transform-origin:

transform-origin can not be that easy simulated using transform: translate. Using transform-origin you change center of transformations, so rotations and all other transforms are calculated based on different point.
Take a look on below example from MDN with transform-origin: 50px,50px. Rotated element is below bottom edge of dotted square by value unable to calculated easily. You could, for sure, simulated transform-origin with transform: translate by values would need to be calculated for particular combination of values.

Related

Does CSS transform: rotate() rotate an image according to its aspect ratio?

I've been given this task as part of an assessment...
"The 'Rotate' button should flip the aspect ratio of the item."
To accomplish this I targeted the element and toggled a class name (rotate) and then added this CSS...
.main-inner.rotate {
transform: rotate(90deg)
}
This works, however, I am wondering if this works with aspect ratio?
Thank you!
div.a {
width: 150px;
height: 80px;
background-color: yellow;
transform: rotate(90deg);
}
<h1>The transform Property</h1>
<h2>transform: rotate(90deg):</h2>
<div class="a">Hello World!</div>
<br>
Yes as this rotate function is developed by professional developers so it must does the related task like rotation

calc() not working with transform in Internet Explorer/Microsoft Edge

I am trying to scale a div by an amount equal to 1/2.9. I can type it as a decimal, but it won't be as accurate as the fraction.
This code works in both IE and Chrome:
.container {
position: absolute;
width: 200px;
height: 290px;
transform: scale(0.3448275862068966);
background: #F00;
}
<div class="container"></div>
However, with calc(), it only works in Chrome:
.container {
position: absolute;
width: 200px;
height: 290px;
transform: scale(calc(1/2.9));
background: #F00;
}
<div class="container"></div>
IE just ignores my calc(1/2.9). It does not scale the container.
Is there anything I can do to make IE correctly render calc()?
No. Since you're not even performing arithmetic with dynamic values here, just do yourself a favor and hardcode the ratio to three decimal places. Three decimal places is all the precision you need, even when taking high-resolution device displays into account.

Skew one corner of image

I'm trying to skew one single corner of my div background as shown at the green checkmark in the image below:
In CSS3 I'm however unable to achieve that, skewing completely skews every corner. I just want to skew the bottom right corner to the left (say 25px) and maintain the perspective (as shown in the image above).
background-image: url('http://rtjansen.nl/images/stackoverflow.png');
-webkit-transform: skew(-45deg);
Fiddle: http://jsfiddle.net/3eX5j/
My code is:
div {
width: 300px;
height:80px;
margin-left:40px;
background-image: url('http://rtjansen.nl/images/stackoverflow.png');
-webkit-transform: skew(-45deg);
}
All you need to do is to think in 3d:
div {
width: 300px;
height:80px;
margin-left:40px;
background-image: url('http://rtjansen.nl/images/stackoverflow.png');
-webkit-transform: perspective(100px) rotateX(-25deg);
-webkit-transform-origin: left center;
-moz-transform: perspective(100px) rotateX(-25deg);
-moz-transform-origin: left center;
}
fiddle
explanation: you are rotating the element towards you in the upper part. But, the perspective (handled though the transform origin, it's a function !) makes the left hand rotation not to translate in an horizontal movement.
See how can be controlled what is the final size
fiddle with multiple options

How to use skew only in the parent element?

Is there any way to use skew only in a parent element?
I need to create something like a 'diamond' as a mask and the child elements can't be affected. There is no way, in this case, to use png as a mask.
Thanks in advance!
It's really easy, you just need to unskew the thing for the children. Unskew means applying another skew transform, but of opposite angle this time.
.parent { transform: skewX(45deg); }
.parent > * { transform: skew(-45deg); }
In general, if you apply a number of transforms on a parent element and you want the child elements to go back to normal, then you have to apply the same transforms, only in reverse order (the order does matter in most cases!) and with a minus for angle/ length values used for skew, rotate or translate. In the case of scale, you need a scale factor of 1/scale_factor_for_parent. That is, for scale, you would do something like this:
.parent { transform: scale(4); }
.parent > * { transform: scale(.25); /* 1/4 = .25 */ }
A diamond shape with children is pretty easy.
DEMO
Result:
HTML:
<div class='wrapper'>
<div class='diamond'>
<div class='child'>Yogi Bear</div>
<div class='child'>Boo Boo</div>
</div>
</div>
CSS:
.wrapper {
overflow: hidden;
margin: 0 auto;
width: 10em; height: 10em;
}
.diamond {
box-sizing: border-box;
margin: 0 auto;
padding: 4em 1em 0;
width: 86.6%; height: 100%;
transform: translateY(-37.5%) rotate(30deg) skewY(30deg);
background: lightblue;
}
.child {
transform: skewY(-30deg) rotate(-30deg);
}
Any transform property affects the element which is applied to and all of his children.
So the only way to skew a single "parent" element is to have it with no children (i.e.: it can't be also a parent!).
Could ou try to elaborate a bit on what do you want to get as a result ?
skew(), like all transform properties always affects the child elements. You could try to use two HTML blocks at the same position, one with the skew() and the other with the contents.
Also, if you just want a diamond, a rectangular box with scale() and rotate() should be enough, but again with no children.
And if you want that diamond as a mask, I'm pretty sure it would be easier to render the parts NOT present in the diamond. Rendering the outside parts of the diamond should not be that hard, after all, they're only rectangle triangles.
the only way to achieve this is to take the child element out of the document flow using position:absolute; and putting an equal negative degree skew on the child.
The problem with this is that you will now have to resize your parent manually.

How to create fluid trapezoid image with css?

I am working on a website on which we have use parallax effect. In that there are some images which are triangle shaped, like this
& the image is transparent because it overlaps the above DIV. I am trying so many things with css. but didn't get the desired result. I achieve that desired result with fixed width. Check this http://jsfiddle.net/eJ7Sf/2/ but does not work with fluid width. Check what i still try but didn't work
http://jsfiddle.net/ceGGN/3/
http://jsfiddle.net/eJ7Sf/1/
NOTE: i know about css3 MASK property but it's not work in firefox previous browsers. I want the capability till firefox 3.6.13
Updated Answer (Pure CSS3)
Extreme requirements sometimes need extreme solutions. I've built upon my original answer (below) to make a pure css solution that works (and can be made to work better, if you want to invest the time in it). The current example is a bit "choppy" in rendering, which may be okay for you, but if not, you will need to extend the already obscene number of #media queries that are driving it (it would likely be much easier to implement using LESS or SASS; I put together a formula driven excel spreadsheet to help rapidly generate the numbers). It uses this code:
HTML
<div class="box">
<img src="yourImage.jpg" />
</div>
CSS
.box{
height:300px;
min-width: 100px; /*could be different, but you ought to have some min*/
overflow:hidden;
}
.box img {
height: 100%;
width: 100%;
-ms-transform-origin: 100% 100%; /* IE 9 */
-webkit-transform-origin: 100% 100%; /* Safari and Chrome */
-moz-transform-origin: 100% 100%; /* Firefox */
-o-transform-origin: 100% 100%; /* Opera */
transform-origin: 100% 100%;
}
/*Sample... you need alot of these--my fiddle example has 51*/
#media screen and (min-width: 100px) {
.box {
-ms-transform:skewY(45deg);
-moz-transform:skewY(45deg);
-webkit-transform:skewY(45deg);
-o-transform:skewY(45deg);
transform:skewY(45deg);
}
.box img {
-ms-transform:skewY(-90deg);
-moz-transform:skewY(-90deg);
-webkit-transform:skewY(-90deg);
-o-transform:skewY(-90deg);
transform:skewY(-90deg);
}
}
Here's how to calculate the degrees
Assuming height: 300px with the narrow side approximately 100px tall and equal angles on the trapezoid. This means the upper and lower offset is (300px - 100px) / 2 = 100px. Then the .box angles are set off the #media query min-width amounts according to this formula:
Angle = arctan(100/min-width) /*100 is the upper/lower offset as above*/
For the .box img angle take the Angle and multiply by -2. So that will yield your .box and .box img media queries and transforms as this pseudocode:
#media screen and (min-width: [your target min-width]) {
.box {transform: skewY(Angle)}
.box img {transform: skewY(-2*Angle)}
}
How smooth it functions depends completely upon how micro scale you make your changes to min-width to get a new angle setting. As I stated in my comment in the CSS code above, my example uses 51 media query calls and still has some choppiness to it.
Would it be better to use some javascript solution instead... probably, but that is totally up to the designer, so I offer this here as purely a proof of concept that it can be made to work with pure css.
Original Answer
This seems to be achieving a fluid width. I don't know how much control you want of either how much or what part of the image is being shown, so it may not entirely fit your needs, but it does make a flexible width image using transforms to give it a fake perspective look.
With SVG clip-path
You can achieve this shape with an inline SVG and the clipPath element :
<svg viewbox="0 0 10 6.7">
<defs>
<clipPath id="clip">
<polygon points="10 0, 10 6.7, 0 4.7, 0 2" />
</clipPath>
</defs>
<image xlink:href="http://i.imgur.com/RECDV24.jpg" x="0" y="0" height="6.7" width="10" clip-path="url(#clip)"/>
</svg>
With CSS clip-path
You can also achieve this shape with the CSS clip-path property. Browser support is pretty low (see canIuse) but it is an easy approach.
Here is an example :
img{
-webkit-clip-path:polygon(0% 20%, 100% 0%,100% 100%,0% 80%);
clip-path:polygon(0% 20%, 100% 0%,100% 100%,0% 80%);
}
<img src="http://i.imgur.com/5NK0H1e.jpg" alt=""/>
If you play a bit with pseudoelements and 2DTransforms (supported since Firefox 3.5) you can achieve this effect : http://jsfiddle.net/fcalderan/T5KPA/1/
I tried on Chrome and Firefox. For Opera and IE9 you need to add proprietary prefixes.
Markup is really essential:
<figure class="triangle">
<img src="http://cssglobe.com/lab/angled/img.jpg">
</figure>
and the css to obtain this effect:
img { display: block; }
.triangle {
position : relative;
overflow : hidden;
padding : 0; margin: 0;
display : inline-block;
}
.triangle:after,
.triangle:before {
content : "";
position : absolute;
z-index : 2;
left : -50%;
width : 200%;
height : 40%;
display : block;
background : #fff;
}
.triangle:before {
top: -24%;
-webkit-transform: rotate(-10deg);
-moz-transform: rotate(-10deg);
transform: rotate(-10deg);
}
.triangle:after {
bottom: -24%;
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
transform: rotate(10deg);
}
I coloured the rotated pseudoelements using white but, of course, you can change the color so it fits the real background color

Resources