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

耗尽温柔 提交于 2019-12-08 05:43:42

问题


I have been playing around with looping of CSS transitions (following this article).

The transition itself could be divided into 4 (looped) phases:
shrinked2=>expanded=>expanded2=>shrinked
These states are represented by 4 classes:
shrinked2 - stateOne
expanded - stateTwo
expanded2 - stateThree
shrinked2 - stateFour

I am, initially, setting the width and height of my element, being transitioned, in percents via id. Then, to trigger transition, I am changing transform: scale via state classes, listed above.

Up to his point it basically works fine for me, here is demonstration on JSFiddle.

Now, as the next step I would like to center the transitioned element, vertically and horizontally, on the page (and keep it there). I am doing so by adding the following, to the element id:
top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); as well as appending each transform:, in the state classes, with translateX(-50%) translateY(-50%). Now this way the scale is not applied to the element (i.e. size is not changed on transition) - only background property is affected, transition only happens once (i.e. it is not looped anymore), as if transitionend was never fired. Here is the result on JSFiddle. Changing of expected property name (in loopTransition function) to background, has not effect (JSFiddle).

I am totally aware that there are lots of other ways to center the element. What I would like to understand is:

  1. Is it possible to combine translateX/translateY and scale in the same CSS transition (if yes, what am I doing wrong?)
  2. If element centering with top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); is not compatible with transitions in general or scale in particular, what is the recommended method to use?

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:


  1. In CSS, #id selectors take precedence over .class selectors. Therefore, the transform declarations in your .state classes never get applied. The solution is to either:

    • increase the specificity of your rule, i.e. #circle.stateTwo,

    • add the !important flag to your declaration:

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

      However this should be avoided and the first method used whenever possible.

  2. An easier method to center elements, that doesn't mix with your animation, is to use 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);
    }
    


来源:https://stackoverflow.com/questions/46705058/is-it-possible-to-combine-translatex-translatey-and-scale-in-single-css-transiti

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!