CSS过渡动画结束后的效果

7
我有一个CSS过渡,可以在悬停时移动元素,并且还有一个在悬停时旋转该元素的动画。动画上有一个延迟,等于过渡持续时间,以便在它到达正确位置后开始动画。这很好用,但是当我们鼠标离开时,动画停止,但它不会返回到初始状态。
请问是否可能在鼠标离开并且动画结束后使其回到初始状态?
你可以在这里看到示例:http://codepen.io/jhealey5/pen/zvXBxM 简化代码如下:
    div {
        width: 200px;
        height: 200px;
        margin: 40px auto;
        background-color: #b00;
        position: relative;

        &:hover {
            span {
                transform: translateY(-60px);
                animation-name: rotate;
                animation-duration: 1s;
                animation-delay: .5s;
                animation-iteration-count: infinite;
                animation-direction: alternate;
            }
        }
    }

    span {
        position: absolute;
        width: 20px;
        height: 20px;
        background-color: #fff;
        bottom: 10px;
        left: 0;
        right: 0;
        margin: auto;
        transition: .5s;
    }

    @keyframes rotate {
        from {
            transform: translateY(-60px) rotate(0);
        }
        to {
            transform: translateY(-60px) rotate(-90deg);
        }
    }

1
我正在使用稍旧版本的Chrome,它在悬停时不进行过渡(动画正常工作)。 - Harry
我认为它在Chrome上无法工作的原因是因为动画和过渡都应用于同一属性(就像在这里讨论的那样)。我认为最好使用动画本身来完成两者。 - Harry
或者,另一个选择是在transition中使用bottom,并且仅在rotate中使用animation,就像这个片段中所示。我不确定这种方法是否适合您的需求。如果适合,请告诉我,我会将其添加为答案。 - Harry
1
我尝试将“top”属性与“translate”分开动画,但似乎直到我设置默认的“top”为0才起作用。动画“top”并不是理想的选择,但我也无法访问DOM来包装它。至少现在可以工作了 :) - evu
这是另一个已知的问题。浏览器不会转换属性值,除非我们有一个像我在这里的回答中提到的初始值。问题并不仅限于Firefox,正如那里的标题所示。 - Harry
2个回答

6

我已经fork了你的项目并将其调整以使其正常工作。 您可以在此处找到它。

我所做的更改如下:

我给白色方块一个起始位置为top: 150px,并在divhover上让它获得top: 0。该标签使用transition: top .5s,因此在悬停时它会转到top: 0;,当鼠标离开时又回到top: 150px;

我已从动画中删除translateY(-60px);,因为这会使animation开始时它往上移动得更多。

这是您的新CSS:

div {
    width: 200px;
    height: 200px;
    margin: 40px auto;
    background-color: #b00;
    position: relative;

    &:hover {
        span {
            top: 0px;
            animation: rotate 1s infinite .5s alternate;
            animation-direction: alternate;
        }
    }
}

span {
    position: absolute;
    width: 20px;
    height: 20px;
    background-color: #fff;
    bottom: 10px;
    left: 0;
    right: 0;
    top: 150px;
    margin: auto;
    transition: top .5s;
}

@keyframes rotate {
    from {
        transform: rotate(0);
    }
    to {
        transform: rotate(-90deg);
    }
}

编辑:问题在于动画是基于时间而不是基于操作的,这意味着一旦你触发了动画,计时器就开始运行,并将运行直到设定的时间已经过去,它将运行所有的关键帧。悬停和悬停-out 没有影响,除非计时器可以被过早停止,但动画将不会继续(或反转,你想要的)之后。转换是基于操作的,这意味着每次发生一个动作(例如:hover),它就会被触发。对于:hover来说,这意味着需要0.5秒才能到达top:0,在悬停结束时,需要0.5秒才能转到top:150px。
我希望上面的内容有意义 :)
正如您所看到的,我还清理了一下您的animation-name:等内容,因为它们可以合并成一行。

我认为(过渡定位属性)是最好的选择,因为animationtransition不能在同一属性上共存。 - Harry
1
谢谢,因为这是最详细的,所以我将其标记为答案。顺便说一下,我在使用git和其他工具时都使用长时间持续性,因为我总是记不住顺序 :) - evu

3
Harry所指出的, 问题在于您正在动画/过渡相同的属性,即transform。看起来当前版本的Chrome / FF将允许animation控制该属性,从而破坏transition。似乎唯一的解决方法是转换/动画不同的属性。由于您需要继续旋转元素,因此可以通过更改bottom属性来平移/定位元素。我知道这不会产生完全相同的结果,但无论如何,它确实移动了元素(只是不相对于父元素)。

更新示例

div:hover  span {
  bottom: 80px;
}

作为替代方案,您还可以包装元素,然后翻译该元素。
在下面的示例中,.wrapper元素在悬停时转换为translateY(-60px),然后子元素被旋转并保持动画。 此处有示例

div {
  width: 200px;
  height: 200px;
  margin: 40px auto;
  background-color: #b00;
  position: relative;
}
div:hover .wrapper {
  transform: translateY(-60px);
}
div:hover .wrapper span {
  animation-name: rotate;
  animation-duration: 1s;
  animation-delay: .5s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}
.wrapper {
  display: inline-block;
  transition: .5s;
  position: absolute;
  bottom: 10px;
  left: 0;
  right: 0;
  text-align: center;
}
.wrapper span {
  display: inline-block;
  width: 20px;
  height: 20px;
  background-color: #fff;
}
@keyframes rotate {
  from {
    transform: rotate(0);
  }
  to {
    transform: rotate(-90deg);
  }
}
<div>
  <span class="wrapper">
   <span></span>
  </span>
</div>


1
不错,Josh。我们似乎又有了相同的想法 :) 我刚在评论中分享了类似的内容。 - Harry
@evu 我刚刚更新了答案。您可以包装 span 元素,然后在保持子元素旋转动画的同时将变换过渡应用于父元素。 - Josh Crozier
你的更新看起来过于复杂了,还是只有我这么觉得? - Rvervuurt
添加一个全新的div,当只需要转换顶部(或底部,在您的情况下)就足够了吗?如果使用transform:很重要,我明白这是必要的,但似乎将translateY(-60px)更改为top: 0;并不是问题。 - Rvervuurt
1
@Rvervuurt 同意。但是无论如何,我想证明仍然可以在产生相同输出的同时过渡/动画化transform属性。例如,如果我们想使用transform: scaleX(2)进行缩放转换并使用其他内容动画化transform属性,则我们将没有替代方法,而此方法将解决该问题。 - Josh Crozier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接