Based on the assumption that Firefox is simply distorted in this regard (see analysis below), here is a workaround that works in Firefox. It wraps the #box element in another div and only translates the wrapper. And the wrapper only rotates 90 degrees from the start point in one direction at a time, so Firefox can't mess it up.
As soon as the transition ends, the reset rotation returns to its original position, and at the same time the inner box rotates to a new position, both without transition, so the change is not visible.
The second important change is the currently computed #box transform and adding rotation to it, so we donβt need to track the turns along the way.
Note that the rotation order matters. In order to achieve what you are trying to do (rotation in "world space" rather than "object space"), you need to apply the rotation in the reverse order. For instance. to rotate to the right, use .css("transform", "rotateY(90deg) " + currentComputedTransform) . This will solve the problem you mentioned in the comments where it rotates around the wrong axis. See below for more details.
Please note that I do not allow the rotation to start if it is already running, because this will not work. You can queue up keystrokes in the array if you want this to be possible, but you can also reduce the length of the transition in proportion to the length of the queue in this case, so it wonβt take forever.
Updated script: https://jsfiddle.net/955k5fhh/7/
Relevant javascript:
$("#box").wrap("<div id='outer'></div>"); var pending=null; function rotate(axis,angle,dir) { if (pending) return; $("#outer").removeClass().addClass(dir); var current=$("#box").css("transform"); if (current=='none') current=''; pending="rotate"+axis+"("+angle+"deg) " + current; } $("#outer").bind('transitionend', function() { $(this).removeClass(); $("#box").css('transform',pending); pending=null; }); $('#up').bind('click', function() { rotate('X',90,"up"); }); $('#down').bind('click', function() { rotate('X',-90,"down"); }); $('#right').bind('click', function() { rotate('Y',90,"right"); }); $('#left').bind('click', function() { rotate('Y',-90,"left"); });
Previous analysis
I played with JS-solutions, and I came across this useful post https://gamedev.stackexchange.com/a/67317 - it indicates that to rotate objects in the "world space" instead of the "object space" you just need to change the rotation order .
Based on this, I simplified your script as follows:
var rot = ""; var tr = "translateZ(-50px)"; $('#up').bind('click', function() { rot=" rotateX(90deg)"+rot; $("#box").css("transform",tr+rot); }); $('#down').bind('click', function() { rot=" rotateX(-90deg)"+rot; $("#box").css("transform",tr+rot); }); $('#right').bind('click', function() { rot=" rotateY(90deg)"+rot; $("#box").css("transform",tr+rot); }); $('#left').bind('click', function() { rot=" rotateY(-90deg)"+rot; $("#box").css("transform",tr+rot); });
https://jsfiddle.net/955k5fhh/ (note that this is not a complete solution, because ultimately the rot string will be too long)
And in Chrome, it behaves as expected. And again, Firefox is mistaken, even if you just chain, for example. rotateX(90deg) transform rotateX(90deg) .
So, I went one step further and turned neighboring rotations on the same axis ...
var rots = []; var tr = "translateZ(-50px)"; function transform() { var tf = "translateZ(-50px)"; rots.forEach(function(rot) { tf += " rotate" + rot[0] + "(" + rot[1] + "deg)"; }); console.log(tf); $("#box").css("transform", tf); } function addRot(axis,angle) { if (rots.length==0 || rots[0][0]!=axis) { rots.unshift([axis,angle]); } else { rots[0][1]+=angle; } transform(); } $('#up').bind('click', function() { addRot('X',90); }); $('#down').bind('click', function() { addRot('X',-90); }); $('#right').bind('click', function() { addRot('Y',90); }); $('#left').bind('click', function() { addRot('Y',-90); });
https://jsfiddle.net/955k5fhh/2/
Which, again, works well in Chrome, and works a little better in Firefox, but still, as soon as you switch the axes, you can end the rotation incorrectly. Similarly, if you press the button before the transition is complete, it may not rotate correctly.
So, I would conclude that, unfortunately, yes, Firefox is just buggy, but at least there are workarounds.