CSS3 Transforms: Multiple Origins? - css

Is it possible to specify an origin at the top left (0%, 0%) for scaling, and a different origin (center) for rotation in CSS3? I am only working with webkit, if that helps.
I am currently using a transform list (i.e. -webkit-transform: scale(newScale) rotate(newRotate)
but it seems like it isn't possible to change the origin in-between passes. Is there a better way to look at this? Presently, if I scale an object and rotate it with an origin at the default center, the position of the element is now off and so when you drag the element, the cursor is still at the top left of the element, whereas it should be at the center. Changing the origin to the center to scale it fixes this, but presents new problems with rotation and flipping.

Found a good solution to the problem... by creating a parent/child relationship as follows:
<div class="container">
<img src="" />
</div>
I can now setup two classes as follows:
.container {
-webkit-transform-origin: 0% 0%;
-webkit-transform: scale(0.5);
}
.container img {
-webkit-transform-origin: 50% 50%;
-webkit-transform: rotate(45deg);
}
This will do exactly what I want: scale with an origin at the top left, then rotate with the origin at the center. Voila!

Instead think of the scaling with origin (0,0) as a scaling+translation with origin center. In isolation the following:
-webkit-transform-origin: top left;
-webkit-transform: scale(1.5);
is the same as:
-webkit-transform-origin: center;
-webkit-transform: scale(1.5) translate3d(16.66%, 16.66%, 0);
In theory the rotation origin center should leave the corners sticking out by sqrt(1/2)-0.5 requiring us to move the origin down and right by 20.71%, but for some reason the webkit transform algorithm moves things down for us (but not quite enough) and scales the origin for us (again not quite). Thus we need to move right by 50% and make some adjustments for this odd behavior:
-webkit-transform-origin: center;
-webkit-transform: scale(1.5) rotate(45deg) translate3d(52.5%, 0.5%, 0);
-webkit-transition: all 2s ease-in;
Note: my original answer was using a div with width:100px; and height100px; which requires a translate3d(54px, 0, 0).

What about that: http://jsfiddle.net/22Byh/1/

Related

Safari transform animation not responding to dynamic width

Having issues making this behave properly on Safari (works fine on Chrome and Firefox): https://jsfiddle.net/my794fyx/4/
In the fiddle, the redbox should move from left to right with a shifting pivot-point. The red box is moved by animating the left property. The pivot-point is shifted by animating translateX().
The importance of having a shifted pivot point comes to play when hovering over the black box: the width of the redbox grows. The direction the red box grows in is determined by the pivot-point -- when the redbox is on the left, it should grow to the right, and when it's on the right, it should grow to the left. This can be seen working properly on Chrome and Firefox.
On Safari, when you hover over the black box and the red box grows in width, it doesn't seem to be taken into account by transform: translateX(-100%). When hovered, the red box exceeds the black box.
Looking for some work-arounds to the browser issue or alternative implementations to the problem.
You might want to try using the -webkit- prefix on the transform and the #keyframes so:
#-webkit-keyframes {
0% {
left: 0%;
-webkit-transform: translateX(0%);
transform: translateX(0%);
}
100% {
left: 100%;
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
}
But just remember that the original must be kept as well! And that you have to add -webkit- prefixes to that for safety, in case one does not support #keyframes without the prefix but not the transform, though it's more likely the other way around, as the above code has.
Also see: here

transform: rotateY() making element disappear

I am trying to apply a simple transform: rotateY(90deg) on an div but it's (the div) disappearing as a result, dev tools is not throwing any error on that line, any suggestions or anything I might be missing?
This happens because when you rotate something on the Y axis by 90 degrees it has spun so that it's essentially facing a different direction. In the below example I've added a transition to show how the element changes over time (hover over it):
figure {
background: red;
height: 100px;
transition: 1s;
width: 100px;
}
div:hover figure {
transform: rotateY(90deg);
}
<div>
<figure></figure>
</div>
As our viewport looks directly onto the element and features no depth, it appears that the element has disappeared altogether.
If we do add some depth, it's easier to visualise what's happening:
The cube on the left is our pre-transform cube and the cube on the right is our cube after it's had rotateY(90deg) applied to it. As we have no depth at all and we're looking at our element front on, we can't see anything when it gets rotated by 90 degrees.

CSS3 Transform only plays first item

I am trying to get my div to rotate 360deg every time I click it, using CSS3 transform rotate. However, I'm also using the CSS3 transform translate to vertically align my div.
On the first click, it applies all the required CSS but doesn't actually rotate, however will rotate all clicks after that. It stays vertically aligned the whole time.
Unsure how to solve this and any help is appreciated :)
My css:
#my-div {
height: 300px;
width: 300px;
transition: all 0.5s ease-in-out;
display: block;
margin: auto;
/*to vertically align*/
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
My javascript
var angle = 360
$('#my-div').click(function() {
$(this).css({
'-webkit-transform' : 'translateY(-50%) rotate('+angle+'deg) ',
'transform' : 'translateY(-50%) rotate('+angle+'deg)'
})
angle += 360
});
In fact the transition works properly only when the 2 ends are explicitly set, here intially the rotate transform is not set explicitly, after the first click, it's explicitly set to rotate(360deg) and hence the next clicks work. To solve this, you just need to apply rotate(0deg) for your div initially via the CSS code:
#my-div {
/*...*/
-webkit-transform: translateY(-50%) rotate(0deg);
transform: translateY(-50%) rotate(0deg);
}
Note that I emphasized on the properly word, in fact if you set the initial angle to some angle equal or smaller than 180deg, you'll see it transitions OK. I doubt that if you don't set the initial rotate transform explicitly, the behavior is determined by the browser, that is 360deg won't make any transition, otherwise the rotating transition may be clockwise (if the angle % 360 is less than or equal to 180deg) and counter-clockwise if the angle % 360 is greater than 180deg (note about the modulo operation between angle and 360).
Demo.

Is there a better way to find out the correct CSS values for a 3D transformation, besides trial & error?

I've got a 3D iPhone vector and I want to have a sprite animation of screens on top of it.
I'm creating a div as mask on top of the iPhone, with the sprite background (animating via transition & background-position).
However, the iPhone is already in the correct 3D position, but in able to use a sprite image in 3D with a mask, the div should be rotated 3D too. Too bad I'm already over an hour trying to figure out the correct values to position the div correctly on top of the iPhone.
I'm currently using the values of: perspective, skew, rotateX, rotateY & rotateZ.
Too bad Photoshop (CC) doesn't give perspective and XYZ-axis values when performing a perspective transformation, otherwise this would be very simple.
So who knows a great way to figure out the correct values, besides trial & error.
Note: I can't use a regular iPhone image and apply 3D values on it and after that, apply the same values to the mask on top of it, because that would mean you'd have a flat 3D object.
Thanks!
current status, with perspective(1000px) rotate(-72deg) rotateX(0deg) rotateY(40deg) rotateZ(11deg) skew(0deg, 20deg); coming from a standard 16:9 portrait image.
It looks like you want some thing along the lines of:
-webkit-transform: rotateX(60deg) rotateY(20deg) rotateZ(-60deg);
-moz-transform: rotateX(60deg) rotateY(20deg) rotateZ(-60deg);
-o-transform: rotateX(60deg) rotateY(20deg) rotateZ(-60deg);
-ms-transform: rotateX(60deg) rotateY(20deg) rotateZ(-60deg);
transform: rotateX(60deg) rotateY(20deg) rotateZ(-60deg);
Given the fact the screen x and y axis are consistent at all four points you should be able to do this without using skew, and likely with a perspective of zero.
Once the eleemnt has been transformed correctly in 3d space, you can shift it on the x and y axis using the transform origin, e.g:
-webkit-transform-origin: 20px 50%;
-moz-transform-origin: 20px 50%;
-o-transform-origin: 20px 50%;
-ms-transform-origin: 20px 50%;
transform-origin: 20px 50%;

Rotate and translate

I'm having some problems rotating and positioning a line of text. Now it's just position that works. The rotation also works, but only if I disable the positioning.
CSS:
#rotatedtext {
transform-origin: left;
transform: rotate(90deg);
transform: translate(50%, 50%);
}
The html is just plain text.
The reason is because you are using the transform property twice. Due to CSS rules with the cascade, the last declaration wins if they have the same specificity. As both transform declarations are in the same rule set, this is the case.
What it is doing is this:
rotate the text 90 degrees. Ok.
translate 50% by 50%. Ok, this is same property as step one, so do this step and ignore step 1.
See http://jsfiddle.net/Lx76Y/ and open it in the debugger to see the first declaration overwritten
As the translate is overwriting the rotate, you have to combine them in the same declaration instead: http://jsfiddle.net/Lx76Y/1/
To do this you use a space separated list of transforms:
#rotatedtext {
transform-origin: left;
transform: translate(50%, 50%) rotate(90deg) ;
}
Remember that they are specified in a chain, so the translate is applied first, then the rotate after that.
Be careful on the "order of execution" in CSS3 chains! The order is right to left, not left to right.
transformation: translate(0,10%) rotate(25deg);
The rotate operation is done first, then the translate.
See:
CSS3 transform order matters: rightmost operation first
There is no need for that, as you can use css 'writing-mode' with values 'vertical-lr' or 'vertical-rl' as desired.
.item {
writing-mode: vertical-rl;
}
Something that may get missed: in my chaining project, it turns out a space separated list also needs a space separated semicolon at the end.
In other words, this doesn't work:
transform: translate(50%, 50%) rotate(90deg);
But this does:
transform: translate(50%, 50%) rotate(90deg) ; /*has a space before ";" */

Resources