I'm having difficulty rotating an item a full 360 degrees in webkit using CSS transitions.
I've created a JS Fiddle to show what I'm trying to do: http://jsfiddle.net/russelluresti/PnTk8/2/
The transition should happen in 2 steps. First, the item should just rotate along the Y axis for a 1/2 turn. Then, once that transition is complete, it should rotate the opposite direction a full turn and scale down to 1/2 the original size. The problem I'm having is that the second transition is only scaling and not rotating, even though rotate values of rotateY(-360deg) and rotateY(0deg) should cause a full rotation.
This is just a proof-of-concept, so I'm only targeting webkit at the moment. However, I'd like to stick with transitions, and not keyframe animations. Any ideas?
In my knowledge, rotate from rotateY(-180deg) to rotateY(-360deg) would be as the same state as rotateY(0). Let's put it this way: imagine you flip a piece of paper twice in the same direction, would be totally the same state as the very beginning. As a result, the browser take it for 'no changes at all', therefore no transition upon the rotation.
another example would make this even clearer:
given deg. set to your case, rotateY(-90deg) => rotateY(-300deg) => rotateY(60deg) would work just the same, the second transition won't start. Becuz relative to the original state: rotateY(0), rotateY(-300deg) is just at the same state as rotateY(60deg).
Related
I'm writing a "3D navigation" where moving the mouse cursor subtlely rotates the contents of the screen. When something is clicked I want it to zoom (scale).
The rotation is achieved with transform property, and evoked when the cursor moves. This part works fine!
Now I want the scale to be animated at 500ms. But if I set this transition speed, it wrecks the nice smoothness of the cursor move property.
I tried solving with JavaScirpt, but the problem is that if I start working the "scale" segment alone, it overwrites the rotation property. CSS doesn't remember that I've set the rotation at some point, if I set transform again, during animation, with only the scale.
I have a work-around, but I don't think it's very nice and I suspect it will difficult to understand and refactor it in the future.
So like I can separate the timing for "background" and "color", is there a way to "go deeper", and also separate for the different transform properties?
Thanks in advance!
Consider this demo: https://jsfiddle.net/s2Lngpto/1/
I have a spinner, and I would like it to spin every time not 360 degrees around but 315 degrees (and go in full cycle in 8 rotations), and CSS is behaving really weirdly. From what I understood, if you specify for example rotate(315deg), it should move to the position -45 degrees of the current position. But instead if moves through the longest path to the right. Okay.. I guess that's just how CSS works, if you specify positive integers it will rotate right, if negative - left? Right... right?
Nope, I've specified the position 270 degrees, and on the second stage it rotates left instead of right
Am I doing something wrong? What is the easiest way to achieve what I want?
As u have awnsered yourself:
in one direction(right):
transform: rotate(10deg)
in the other direction(left):
transform: rotate(-10deg)
It probably has to do with your animation, when you have the attribute animation: alternate for example it tends to do as u described. Could u provide some code?
I found a strange behavior when transitioning between visibility hidden and visible. It seems like when going to visible, it immediately becomes visible at the start of the transition duration. But going back to hidden, it waits until the transition duration has completed before disappearing.
What's the reason for this? Is this something I can rely on, or should I explicitly set their transition delays?
The reason for this is because that is the recommended implementation for transitioning the visible property:
From the W3 for CSS Transitions:
visibility: if one of the values is ‘visible’, interpolated as a discrete step where values of the timing function between 0 and 1 map to ‘visible’ and other values of the timing function (which occur only at the start/end of the transition or as a result of ‘cubic-bezier()’ functions with Y values outside of [0, 1]) map to the closer endpoint; if neither value is ‘visible’ then not interpolable.
Basically, visible is used whenever the transition percentage is not 0.00 (or 1.00). So, if the transition percentage is, say, 10% (0.1), then it is visible. That is why it becomes visible immediately. The other values aren't recognized until the transition is fully complete, because visible is used during the transition.
Depending on your use-case, you can use transition-delay, you can use a keyframe animation, you can transition the opacity property, or you can try to use cubic-bezier functions.
In first excuse me for my bad english, I'm French. I'll do the best ! I'm here today because for the first time i don't find an answer to my problem. Monday i need to show a demo of a website and i start to panic !
So, I have a div with a rotate (45deg). Within this div, I have two div other div in inline-block (with a css rotate (-45deg). On the left i have a slider and on the right text and shortcuts. Today I joined the slider to the left position (I work on joomla). It works well but I have a problem with the slide transition. If I click "next" or "previous", the global div (the main container) becomes blurred for the duration of transition. I did screenshots of the text on the right position (best seen the difference).
Fiddle for example :
http://jsfiddle.net/asakuras/8Pk3S/11/
Pics for example :
Before click and just after the click, during the transition :
http://www.morgann-c.com/tools/js/bug.jpg
Explanations :
I tested many possibility to clean that but no solution at this time. In the script (responsiveslides.js) the transition's are reduction by the opacity. At the line 71 of the script there's the configuration of the opacity :
visible = {"float": "left", "position": "relative", "opacity": 1, "zIndex": 2},
hidden = {"float": "none", "position": "absolute", "opacity": 0, "zIndex": 1, }
If I change the opacity of the hidden class to 0 there's no transition but the bug disappears ! I think this is a problem with the CSS's opacity transition. If I delete the rotate on all the div's the bug also disappears. I tested all the CSS transform but no result ...
I'm working on this bug for 3 days and it's very important for me to find a solution quickly ...
I implore you, if someone has already had this problem i take !
Have a good week end and thank you by advance ...
EDIT //// :
Firefox 30 : "Blur" on click
Chrome 35.0.1916.153 : "Blur" everywhere on page load
IE 11 : No problems, no "blur", everything works perfectly !
First off, you were missing a - in -ms-transform (this is likely the reason why there is no blur in IE - it wasn't using transform)
Secondly, removing -webkit-backface-visibility made it so Chrome only blurs on the transition (I have no idea why you added it given nothing rotates at all).
Thirdly unless you're serving IE8- or something like that you don't need filter for the rotation and -o-transform and -moz-transform are not needed, so remove them
Lastly, the reason why it's blurry is because it's being rendered by the GPU. Though this does always happen when things are generated by the GPU, but I'm thinking that it is simply being overworked by the fact that there are two rotations and in addition to the opacity transition.
Thus, as a solution you have a few options. You can either remove the opacity transition, opting for something like margin-left:-600px (this requires changing the plugin to suit), you could move the header and paragraph outside of <div id="global"> but position it so that it's in the same position as it currently is (making sure none goes outside of the rotated square), or, my personal favorite choose another plugin! The one you're using is quite outdated and there are a lot better free ones just one Google search away
I'm working on a full screen image viewer, I'll temporarily open a dev URL here:
http://www.jungledragon.org/apps/jd3/image/704/great_grey_owl.html/zoom
This viewer is responsive and scales to your browser width/height. One of its key features is being able to zoom in and out of the image using your mouse wheel. Rather than a center-based zoom, the idea is to zoom based on origin, meaning the coordinates of your mouse, allowing you to zoom into specific areas of the image.
How to reproduce the issue
If you open the above URL and have a quick play with your mouse wheel, it may appear to be working correctly. However, the math I am using is slightly off. Here is how you can reproduce the issue:
Open the above URL
Hover your mouse over the left eye of the Owl
Zoom one step using your mouse wheel, it should zoom exactly into the eye
Position your mouse on the owl's beak
Zoom one more step using your mouse wheel
You should now notice that the second zoom step did not go into the Owl's beak exactly, it seems to be slightly off, both horizontally and vertically. I'm thinking this is a result of bad math.
How it works
Here is the javascript that handles it all:
http://www.jungledragon.org/apps/jd3/js/jd3-slideshow.js
I am capturing the mousewheel event. Based upon its direction, I am increasing or decreasing the zoom level. The actual zooming is nothing more than applying a CSS class that scales the image using a CSS3 transform:
&.grow1 { #include jd-scale(1); }
&.grow2 { #include jd-scale(1.5); }
&.grow3 { #include jd-scale(2.0); }
&.grow4 { #include jd-scale(2.5); }
&.grow5 { #include jd-scale(3.0); }
Note: the above is a call to a SASS mixin that translates into the right vendor prefixes for transform:scale.
The above accomplishes the basic zooming without issues. To make origin-based zooming possible, however, a few more steps are needed. Upon doing the actual zooming, I first set the origin of the zoom in javascript, using transform-origin. Here is my helper function for setting it:
function zoomOrigin(selector, originStr) {
selector.css({'-webkit-transform-origin': originStr});
selector.css({'-moz-transform-origin': originStr});
selector.css({'-ms-transform-origin': originStr});
selector.css({'-o-transform-origin': originStr});
selector.css({'transform-origin': originStr});
}
The heart of this question is about calculating the correct origin. There are two things worthy to mention in calculating this value:
The absolute coordinates (meaning the X and Y) are relative to the image, not relative to the page
The calculation of the origin should take into account that the image has grown/shrunk based on the current zoom state
The origin calculation happens in realtime, based on the mousemove event. Here is the method that does so, with irrelevant parts removed:
$("#image-container img").mousemove(function(e) {
// user has moved their mouse. in case of zooming or panning, this means that the
// origin (center point) of those interactions need to be recalculated
// calculate the mouse offset within the zoomable object (which is different than the page-level offset)
// this relies on the parent of the element having position:relative set
var parentOffset = $(this).offset();
zoomOriginX = e.pageX - parentOffset.left;
zoomOriginY = e.pageY - parentOffset.top;
// recalculate the width and height of the image given the current zoom level
width = $(this).outerWidth() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerWidth());
height = $(this).outerHeight() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerHeight());
// calculate origin percentages based on zoomed width and height
// the zoom methods rely on these variables to be set
zoomOriginPercX = (zoomOriginX / width * 100);
zoomOriginPercY = (zoomOriginY / height * 100);
});
The main purpose of this method is to correctly set the global variables zoomOriginPercX and zoomOriginPercY, which are used to set the origin (percentage) prior to zooming.
From a math perspective, my idea was to simply calculate the zoomed width of the image, and to use the offset X and Y to come to a reliable origin percentage. As the problem statement shows, I am quite close to a correct calculation, yet something is off.
Although the zooming currently works well, I want it to be perfect. It would make for quite a powerful image viewer that is really easy to implement, also for others.
Desired Effect
To start answering your question I think it's worth first clarifying the desired effect. Essentially you're looking for the same effect you'd get if you pinched to zoom on an iPhone - the 'origin' of the pinch stays exactly the same, and everything around it stretches. You can imagine pinning some stretchy fabric at the origin, and pulling the corners.
Problem
This is working fine for you if you don't move the mouse between zooms, but if you do, the origin appears to move. The cause of the problem is exactly that - you are changing the origin of the transform every time you move the mouse. Of course you do need to do this, but you are calculating the origin based on the original (100% zoomed) position of the image. The actual origin needs to be somewhere between the origin of the first zoom and the new mouse position.
In other words, CSS is just doing one transform. If you set the origin to x,y then zoom to zoom level 2, this will give the same result as if you set the origin to x2,y2, zoom to level 1, then move to x,y, and go to level 2.
Solutions
I presume you could solve the issue in several ways:
Calculate a scaling factor for the 'new' origin on each zoom
this is likely a function of zoom level, mouse position and previous origin
Calculate and apply a translation each time the origin is moved
again will depend on the current origin, zoom level and mouse position
Find another way to 'stack' transforms on top of one another.
One way to do this may be to dynamically generate a new containing div each time you and apply a scale transform to that similar to the accepted solution in this question.
Unfortunately I don't have the time to go further than this, but hopefully it points you in the right direction?