是否可以在单个 CSS 转换中组合 translateX/translateY 和缩放?

Is it possible to combine translateX/translateY and scale in single CSS transition?

我一直在玩 CSS 转换循环(在 this article 之后)。

过渡本身可以分为 4 个(循环)阶段:
收缩2=>扩展=>扩展2=>收缩
这些状态由 4 类:
表示 收缩2 - stateOne
扩展 - stateTwo
扩展2 - stateThree
收缩2 - stateFour

最初,我通过 id 以百分比设置要转换的元素的宽度和高度。然后,为了触发转换,我正在通过上面列出的状态 类 更改 transform: scale

就他而言,它对我来说基本上工作正常,这里是 demonstration on JSFiddle

现在,作为下一步,我想将过渡元素在页面上垂直和水平居中(并保持在那里)。我通过向元素 id 添加以下内容来这样做:
top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); 以及在状态 类 中为每个 transform: 附加 translateX(-50%) translateY(-50%)。现在这样 scale 不应用于元素(即大小在过渡时不改变) - 只有 background 属性 受到影响,过渡只发生一次(即它不再循环),就好像 transitionend 从未被解雇过一样。 这里是 the result on JSFiddle. Changing of expected property name (in loopTransition function) to background, has not effect (JSFiddle).

我完全知道有 lots of other 种方法可以使元素居中。我想了解的是:

  1. 是否可以将 translateX/translateYscale 组合在同一个 CSS 转换中(如果是,我做错了什么?)
  2. 如果 top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); 的元素居中与一般的过渡或特定的 scale 不兼容,建议使用什么方法?

var the_circle = document.getElementById('circle');
the_circle.addEventListener("transitionend", loopTransition);

function startTransition() {
    var the_circle = document.getElementById('circle');
    if (the_circle.className === 'stateOne paused') {
        the_circle.style.transitionDuration = 1;
        the_circle.className = 'stateTwo animated';
    } else {
        stopTransition();
    }
}

function stopTransition() {
    var the_circle = document.getElementById('circle');
    the_circle.style.transitionDuration = "0.5s"
    the_circle.className = "stateOne paused"
}

function loopTransition(e) {
    var the_circle = document.getElementById('circle');
    if (e.propertyName === "transform") {
        if (the_circle.className.indexOf('paused') !== -1) {
            stopTransition()
        } else {
            if (the_circle.className === "stateTwo animated") {
                the_circle.style.transitionDuration = "1s";
                the_circle.className = "stateThree animated";
            } else if (the_circle.className === "stateThree animated") {
                the_circle.style.transitionDuration = "1s";
                the_circle.className = "stateFour animated";
            } else if (the_circle.className === "stateFour animated") {
                the_circle.style.transitionDuration = "1s";
                the_circle.className = "stateOne animated";
            } else if (the_circle.className === "stateOne animated") {
                the_circle.style.transitionDuration = "1s";
                the_circle.className = "stateTwo animated";
            }
        }
    }
}
#circle {
    top: 50%;
    left: 50%;
    transform: translateX(-50%) translateY(-50%);
    position: absolute;
    width: 10%;
    padding-top: 10%;
    border-radius: 50%;
    transition: all 1s;
}

.stateOne {
    background: #800080;
    transform: scale(1.0001, 1.0001) translateX(-50%) translateY(-50%);
}

.stateTwo {
    background: #ffe6ff;
    transform: scale(2, 2) translateX(-50%) translateY(-50%);
}

.stateThree {
    background: #ffe6ff;
    transform: scale(2.0001, 2.0001) translateX(-50%) translateY(-50%);
}

.stateFour {
    background: #800080;
    transform: scale(1, 1) translateX(-50%) translateY(-50%);
}
<div id='circle' class="stateOne paused" onclick=startTransition()></div>

  1. 在 CSS 中,#id 选择器优先于 .class 选择器。因此,.state 类 中的 transform 声明永远不会被应用。解决方案是:

    • 增加规则的 specificity,即 #circle.stateTwo

    • !important 标志添加到您的声明中:

      transform: scale(2, 2) translate(-50%, -50%) !important;
      

      但是应该避免这种情况,尽可能使用第一种方法。

  2. 一种不与动画混合的更简单的居中元素方法是使用 flexbox:

    .flex-container {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100vw;
      height: 100vh;
    }
    
    #circle {
      width: 10%;
      padding-top: 10%;
      border-radius: 50%;
      transition: all 1s;
    }
    
    .stateOne {
      background: #800080;
      transform: scale(1.0001, 1.0001);
    }
    
    .stateTwo {
      background: #ffe6ff;
      transform: scale(2, 2);
    }
    
    .stateThree {
      background: #ffe6ff;
      transform: scale(2.0001, 2.0001);
    }
    
    .stateFour {
      background: #800080;
      transform: scale(1, 1);
    }