Firefox CSS旋转与Chrome旋转不同 [英] Firefox CSS rotation differs from Chrome rotation

查看:86
本文介绍了Firefox CSS旋转与Chrome旋转不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制作一个3D矩形(平行六面体),用户可以用箭头移动它。它在Chrome中运行良好,但在Firefox中,一些转换(实际上很多)与Chrome不同。看看这个小提琴(这是我的整个代码),并在两个浏览器中进行比较,以便更好地理解。

I want to make a 3D rectangle (parallelepiped) which the users can move with the arrows. It works fine in Chrome, but in Firefox some transitions (a lot actually) are different from Chrome. Look at this fiddle (this is my whole code) and compare it in both browsers to understand better.

因为第一个小提琴包含很多代码,我会简化它并选择一个随机奇怪的转换。查看这个小提琴,然后按向左按钮或向左箭头一次。它工作正常,但当你再次按下它时,矩形旋转3次而不是1次。

Because the first fiddle contains a lot of code, I'll simplify it and pick one random strange transition. Look at this fiddle, and press the "Left" button or the left arrow one time. It works fine, but when you press it again, the rectangle rotates 3 times instead of 1 time.

这是一个Firefox错误还是我做错了什么?

Is this a Firefox bug or what am I doing wrong?

下面的代码就是你要做的找到简化的小提琴。

The code below is what you'll find in the simplified fiddle.

var position = 'show-front';

$('#left').bind('click', function() {
    if (position == 'show-front') {
        $('#box').removeClass().addClass('show-right');
        position = 'show-right';
    } else if (position == 'show-right') {
        $('#box').removeClass().addClass('show-back-3');
        position = 'show-back-3';
    } else if (position == 'show-back-3') {
        $('#box').removeClass().addClass('show-left');
        position = 'show-left';
    } else if (position == 'show-left') {
        $('#box').removeClass().addClass('show-front');
        position = 'show-front';
    }
});
    
$(window).bind('keyup', function(event) {
    switch (event.keyCode) {
        case 37: // left
            $('#left').click();
            break;
    }
});

.container {
width: 150px;
height: 100px;
position: relative;
margin: 25px auto 25px auto;
perspective: 600px;
}

#box {
    width: 100%;
    height: 100%;
    position: absolute;
    transform-style: preserve-3d;
    transition: transform 1s;
}

#box figure {
    display: block;
    position: absolute;
    border: 1px solid black;
    line-height: 98px;
    font-size: 45px;
    text-align: center;
    font-weight: bold;
    color: white;
}

figure {
    margin: 0;
}

#box .front,
#box .back {
    width: 148px;
    height: 98px;
}

#box .right,
#box .left {
    width: 48px;
    height: 98px;
    left: 50px;
}

#box .top,
#box .bottom {
    width: 148px;
    height: 48px;
    top: 25px;
    line-height: 48px;
}

#box .front {
    background: hsla(000, 100%, 50%, 0.7);
}

#box .back {
    background: hsla(160, 100%, 50%, 0.7);
}

#box .right {
    background: hsla(120, 100%, 50%, 0.7);
}

#box .left {
    background: hsla(180, 100%, 50%, 0.7);
}

#box .top {
    background: hsla(240, 100%, 50%, 0.7);
}

#box .bottom {
    background: hsla(300, 100%, 50%, 0.7);
}

#box .front {
    transform: translateZ(25px);
}

#box .back {
    transform: rotateX(180deg) translateZ(25px);
}

#box .right {
    transform: rotateY(90deg) translateZ(75px);
}

#box .left {
    transform: rotateY(-90deg) translateZ(75px);
}

#box .top {
    transform: rotateX(90deg) translateZ(50px);
}

#box .bottom {
    transform: rotateX(-90deg) translateZ(50px);
}

#box.show-front {
    transform: translateZ(-50px);
}

#box.show-right {
    transform: translateZ(-150px) rotateY(-90deg);
}

#box.show-back-3 {
    transform: translateZ(-50px) rotateX(180deg) rotateZ(-180deg);
}

#box.show-left {
    transform: translateZ(-150px) rotateY(90deg);
}

<section class="container">
    <div id="box" class="show-front">
        <figure class="front">1</figure>
        <figure class="back">2</figure>
        <figure class="right">3</figure>
        <figure class="left">4</figure>
        <figure class="top">5</figure>
        <figure class="bottom">6</figure>
    </div>
</section>

推荐答案

基于假设Firefox在这方面只是错误(见下面的分析),这是一个适用于Firefox的解决方法。它将 #box 元素包装在另一个 div 中,并且只转换包装器。并且包装器一次只能从一个方向从起点旋转90度,因此Firefox无法搞砸它。

Based on the assumption that Firefox is just buggy in this regard (see analysis below), here is a workaround that works on Firefox. It wraps the #box element in another div, and only transitions the wrapper. And the wrapper is only ever rotated 90 degrees from the starting point in one direction at a time, so Firefox can't mess it up.

转换完成后,旋转重置回起始位置,同时内框旋转到新位置,两者都没有过渡,因此变化不可见。

Once the transition finishes, the rotation is reset back to the starting position and simultaneously the inner box is rotated to the new position, both without transition, so the change is not visible.

第二个重要变化正在使用 #box 的当前计算转换并将旋转添加到该转换,以便我们不必跟踪旋转。

The second important change is using the current computed transformation of #box and adding the rotation to that, so that we don't have to keep track of the rotations as we go.

请注意,轮换顺序很重要。要实现您想要做的事情(在世界空间而不是对象空间中旋转),您需要以相反的顺序应用旋转。例如。要向右旋转,请使用 .css(transform,rotateY(90deg)+ currentComputedTransform)。这将解决您在评论中提到的问题,它似乎围绕错误的轴旋转。有关详细信息,请参见下文。

Note that the order of rotations matters. To achieve what you're trying to do (rotating in "world space" rather than "object space"), you need to apply the rotations in reverse order. E.g. to rotate "right", use .css("transform", "rotateY(90deg) " + currentComputedTransform). This will resolve the issue you mentioned in comments where it appears to rotate around the wrong axis. See below for more information.

另请注意,如果已经有一个轮换,我不允许轮换启动,因为这不起作用。如果你希望能够在数组中排队击键,你可以排队,但是在这种情况下你可能还希望减少与队列长度成比例的转换持续时间,因此不需要永远。

Note also that I don't allow a rotation to start if there's already one in progress, because that won't work. You could queue up keystrokes in an array if you want to be able to that, but you might also want to reduce the transition duration proportional to queue length in that case so it doesn't take forever.

更新小提琴: https://jsfiddle.net/955k5fhh/7/

相关的javascript:

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");
});






上一个分析



我一直在玩基于JS的解决方案,我遇到了这个有用的帖子 https:// gamedev。 stackexchange.com/a/67317 - 它指出要在世界空间而不是对象空间中旋转对象,您只需要反转旋转的顺序。


Previous analysis

I've been playing with JS-based solutions and I came across this useful post https://gamedev.stackexchange.com/a/67317 - it points out that to rotate objects in "world space" instead of "object space", you just need to reverse the order of the rotations.

基于此,我将您的小提琴简化为以下内容:

Based on that, I simplified your fiddle to the following:

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/ (请注意,这不是一个完整的解决方案,因为最终 rot 字符串会变得太长)

https://jsfiddle.net/955k5fhh/ (note that it's not a complete solution, because eventually the rot string will get too long)

在Chrome上,行为符合预期。再次,Firefox错了,即使你只是链接,例如一系列 rotateX(90deg)转换。

And on Chrome, that behaves as expected. And once again, Firefox gets it wrong, even if you're just chaining e.g. a sequence of rotateX(90deg) transformations.

所以我更进了一步,并在同轴......

So I went one step further and rolled up adjacent rotations in 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/

这再次适用于Chrome,效果更好Firefox,但是一旦你切换轴,你就可以以错误的方式旋转。同样,如果你在转换完成之前单击一个按钮,它可能会以错误的方式旋转。

Which, again, works well in Chrome, and works a bit better in Firefox, but still once you switch axes, you can wind up spinning the wrong way. And similarly if you click a button before a transition completes, it can spin the wrong way.

所以我会得出结论,不幸的是,Firefox在这方面只是错误,但是至少有解决方法。

So I would conclude that unfortunately yes, Firefox is just buggy in this, but at least there are workarounds.

这篇关于Firefox CSS旋转与Chrome旋转不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆