是否可以在单个 CSS 过渡中结合 translateX/translateY 和缩放?

Posted

技术标签:

【中文标题】是否可以在单个 CSS 过渡中结合 translateX/translateY 和缩放?【英文标题】:Is it possible to combine translateX/translateY and scale in single CSS transition? 【发布时间】:2018-03-24 02:56:44 【问题描述】:

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

过渡本身可以分为 4 个(循环)阶段:shrinked2=>expanded=>expanded2=>shrinked 这些状态由 4 个类表示:shrinked2 - stateOne expanded - stateTwo expanded2 - stateThree shrinked2 - 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。将预期的属性名称(在loopTransition 函数中)更改为background、has not effect (JSFiddle)。

我完全知道有lots 的other 方法来居中元素。我想了解的是:

    是否可以在同一个 CSS 过渡中组合 translateX/translateYscale(如果是,我做错了什么?) 如果以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>

【问题讨论】:

你试过animation & keyframes吗? @Svenskunganka 是的,我有,(请参阅:another question 和 JSFiddle),它工作得非常好。不过,由于我正在为学习目的做这些事情,我的目标是让它现在与 transition 一起工作。 【参考方案1】:

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

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

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

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

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

    一种不与动画混合的更简单的居中元素方法是使用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);
    
    

【讨论】:

我假设 leftright 按百分比定位不考虑 scale 转换,但 translate 会。稍后我可能会对此进行测试... 第一个建议的方法(使用#circle.stateTwo)最初使元素居中,尽管fails (JSFiddle) 使其在过渡期间保持居中,但我很感激并解释为什么会发生这种情况。第二种,方法(使用flexbox)works (JSFiddle) 符合预期,所以我想我会坚持下去。无论如何,感谢您的回答!

以上是关于是否可以在单个 CSS 过渡中结合 translateX/translateY 和缩放?的主要内容,如果未能解决你的问题,请参考以下文章

在 Firefox 中结合 CSS 过渡和动画

css3中transition 过渡效果如何只对transform:scale 起作用,对其它像transform: translate不起作用!

CSS过渡混合绝对和相对定位

下拉列表的过渡效果

GTK+ 中的 CSS 过渡/动画。是不是可以?

UICollectionView 在过渡期间为单个项目设置动画