如何播放用于悬停的反向关键帧动画? [英] How to play reverse keyframe animation for hover off?

查看:88
本文介绍了如何播放用于悬停的反向关键帧动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图建立一个下拉菜单,首先下拉菜单向下滑动,然后从底部显示一个一个的菜单项。悬停时,它看起来不错,但我不知道如何在悬停时顺利地播放它。我想要做的是先隐藏第二个子菜单项,然后是第一个子菜单项,然后下拉框向上滑动。

我尝试的是在默认情况下将隐藏动画关键帧添加到下拉列表中,并在悬停时添加显示动画,延迟时间为0。但它不能正常工作,因为你可以看到。(它也会在页面加载时动画,这对我不好)。 > ul li ul {
-webkit-animation:hideDropdown 1s;
-webkit-animation-delay:0.5s;
}

ul li:hover ul {
-webkit-animation:showDropdown 1s forwards;
-webkit-animation-delay:0s;
}

小提琴演示(使用SCSS)

解决方案

产生动画相反效果的问题总是很复杂。这不是不可能的,但它需要额外的编码(如额外的关键帧)和调整所有相关的属性,以达到完美的效果。



使用如果需要实现相反效果,则转换是最佳选择。使用过渡效果完全可以产生效果,这与使用动画的方式非常相似。在:hover 选择器中,应用转换设置,使得:first-child 的延迟比第二个(及后面的子代)低,所以它首先出现,并且在默认选择器中应用转换设置,使得:first-child 的延迟比其他的要高。



使用转换也可以避免页面加载时显示动画。这是因为转换只发生在状态从一个状态转换到另一个状态时发生。



body {background:#f1f1f1 ;} ul {height:100px;位置:相对;背景:#fff;} ul li {display:block;向左飘浮;保证金:0; list-style-type:none; padding:0;} ul li a {display:block; height:100px; line-height:100px; padding:0 20px;} ul li ul {position:absolute; left:0px; right:0px; top:100px; height:0px;不透明度:0;知名度:隐藏; transition:all 1s 0.5s;} ul li ul li {position:absolute; left:50px; bottom:0px;宽度:200px;溢出:隐藏; height:100px;} ul li ul li a {display:block; height:100px;背景:红色; padding:0 20px;位置:绝对;不透明度:0; transform:translate(0px,100px); transition:all 1s 0.2s;} ul li li:first-child a {transition-delay:0.4s;} ul li li:last-child {left:250px;} ul li li:last-child a { transition-delay:0.2s;} ul li:hover ul {height:100px;不透明度:1;可见度:可见的; transition:all 1s 0s;} ul li:hover ul li a {opacity:1; transform:translate(0px,0px); transition:all 1s 0.2s;} ul li:hover ul li:last-child a {transition-delay:0.4s;}

 < ul> <李> < a href =#>下拉式广告< / a> < UL> < li>< a href =>第一个< / a>< / li> < li>< a href =>第二< / a>< / li> < / UL> < /锂> < li>< a href =>不下拉< / a>< / li>< / ul> 



注意:在上面的代码片段中,我使用了已编译的CSS并删除了所有 -webkit- 前缀可以在所有浏览器上显示。如果你想要带有前缀的SCSS代码,你可以在这里找到它。






所有这一切,我仍然想解释是什么造成了动画演示的问题。你做了很多正确的工作,你几乎接近实现你想要的。



动画的工作方式是,一旦应用动画的选择器是不再适用,动画将被移除(丢失),并且元素会立即恢复到其默认或原始状态。即使在悬停时应用另一个动画,在逆向动画的关键帧设置中指定的属性也不会在 应用到延迟时间 之前应用。这意味着 ul a 会回到不可见状态(通过 opacity code>或 visibility )设置,当动画开始时(通过 keyframe <>)再次变为可见,然后动画到结束状态(通过关键帧再次不可见)。

解决这个问题的方法是将 animation-fill-mode:backwards 设置为 ul a (未隐藏状态)。此设置意味着即使在延迟期间,该元素也会从关键帧的<中指定的属性。



  body {background:#f1f1f1;} ul {height:100px;位置:相对;背景:#fff;} ul li {display:block;向左飘浮;保证金:0; list-style-type:none; padding:0;} ul li a {display:block; height:100px; line-height:100px; padding:0 20px;} ul li ul {position:absolute; left:0px; right:0px; top:100px; height:0px;知名度:隐藏;动画:hideDropdown 1s;动画延迟:0.5s; animation-fill-mode:backwards;} ul li ul li {position:absolute; left:50px; bottom:0px;宽度:200px;溢出:隐藏; height:100px;} ul li ul li a {display:block; height:100px;背景:红色; padding:0 20px;位置:绝对;不透明度:0; transform:translate(0px,100px);动画:hideDropdownItem 1s 0.2s; animation-fill-mode:backwards;} ul li li:first-child a {animation-delay:0.4s;} ul li li:last-child {left:250px;} ul li li:last-child a {animation-delay:0.2s;} ul li:hover ul {animation:showDropdown 1s forwards;动画延迟:0s;} ul li:hover ul li a {animation:showDropdownItem 1s转发0.2s;} ul li:hover ul li:last-child a {animation-delay:0.4s;} @ keyframes showDropdown {from {不透明度:0;身高:0;知名度:隐藏; }到{height:100px;不透明度:1;可见度:可见的; }} @ keyframes hideDropdown {from {height:100px;不透明度:1;可见度:可见的; }到{不透明度:0;身高:0;知名度:隐藏; }} @ keyframes showDropdownItem {{{opacity:0; transform:translate(0px,100px); }到{不透明度:1; transform:translate(0px,0px); }} @ keyframes hideDropdownItem {{{opacity:1; transform:translate(0px,0px); }到{不透明度:0; transform:translate(0px,100px); }}  

< ul> <李> < a href =#>下拉式广告< / a> < UL> < li>< a href =>第一个< / a> < /锂> < li>< a href =>第二个< / a> < /锂> < / UL> < /锂> < li>< a href =>不下拉< / a> < / li>< / ul>

注意:与第一个片段相同,上面的代码也使用纯CSS,没有前缀。带有前缀的SCSS版本可在这里找到。



但如前所述,这不会阻止在页面加载时显示动画。唯一的方法就是使用JavaScript。


I'm trying to build a dropdown menu where first the dropdown slides down, then one-by-one menu items appear from the bottom. On hover, it looks good but I don't know how to play it smoothly on hover off. What I'm trying to do is hide the second sub-menu item first, then the first submenu item, then the dropdown slides up.

What I tried is to add the hide animation keyframes with a delay by default to the dropdown, and add the show animation on hover with 0 delay. But its not working properly as you can see.(and it will animate on page load too, which is not good for me)

ul li ul {
  -webkit-animation: hideDropdown 1s;
  -webkit-animation-delay: 0.5s;
}

ul li:hover ul {
  -webkit-animation: showDropdown 1s forwards;
  -webkit-animation-delay: 0s;
}

Fiddle Demo (uses SCSS)

解决方案

As I had indicated in comments to the question, producing the reverse effect of an animation is always complex. It is not impossible but just that it requires extra coding (like extra keyframes) and tweaking of all related properties to achieve a perfect effect.

Using transition is the best option if there is a need to achieve the reverse effect also. It is perfectly possible to produce the effect that you are after using transitions and it is all very similar to how you'd do it with animations. In the :hover selector, apply the transition setting such that :first-child has a lower delay than the second (and subsequent children) so that it appears first and in the default selector apply the transition setting such that the :first-child has a higher delay than the rest.

Using transitions would also avoid the animation being shown on page load itself. This is because the transitions only happen when there is a state change from one to another.

body {
  background: #f1f1f1;
}

ul {
  height: 100px;
  position: relative;
  background: #fff;
}
ul li {
  display: block;
  float: left;
  margin: 0;
  list-style-type: none;
  padding: 0;
}
ul li a {
  display: block;
  height: 100px;
  line-height: 100px;
  padding: 0 20px;
}
ul li ul {
  position: absolute;
  left: 0px;
  right: 0px;
  top: 100px;
  height: 0px;
  opacity: 0;
  visibility: hidden;
  transition: all 1s 0.5s;
}
ul li ul li {
  position: absolute;
  left: 50px;
  bottom: 0px;
  width: 200px;
  overflow: hidden;
  height: 100px;
}
ul li ul li a {
  display: block;
  height: 100px;
  background: red;
  padding: 0 20px;
  position: absolute;
  opacity: 0;
  transform: translate(0px, 100px);
  transition: all 1s 0.2s;
}
ul li ul li:first-child a {
  transition-delay: 0.4s;
}
ul li ul li:last-child {
  left: 250px;
}
ul li ul li:last-child a {
  transition-delay: 0.2s;
}
ul li:hover ul {
  height: 100px;
  opacity: 1;
  visibility: visible;
  transition: all 1s 0s;
}
ul li:hover ul li a {
  opacity: 1;
  transform: translate(0px, 0px);
  transition: all 1s 0.2s;
}
ul li:hover ul li:last-child a {
  transition-delay: 0.4s;
}

<ul>
  <li>
    <a href="#">Dropdown</a>
    <ul>
      <li><a href="">First</a></li>
      <li><a href="">second</a></li>
    </ul>
  </li>
  <li><a href="">Not dropdown</a></li>
</ul>

Note: In the above snippet, I've used the compiled CSS and removed all the -webkit- prefixes to make it viewable on all browsers. If you want the SCSS code with the prefixes, you can find it here.


All that said, I still want to explain what was creating the problem with your animation demo. You had done a lot of work correct and you were almost close to achieving what you want.

The way animations work is such that once the selector that is applying the animation is not applicable any longer, the animation gets removed (lost) and the element immediately snaps back to its default or original state. Even though another animation was being applied on hover out, the properties specified within the reverse animation's keyframe settings do not get applied until their delay time is elapsed. This means that the ul and a snap back to being invisible (either through opacity or visibility) setting, become visible again when the animation starts (through from keyframe) and then animate to the end state (again invisible through the to keyframe).

The solution to this problem is to set animation-fill-mode: backwards to the ul and a (unhovered state). This setting would mean that the element takes the properties specified in the from keyframes even during the delay period.

body {
  background: #f1f1f1;
}
ul {
  height: 100px;
  position: relative;
  background: #fff;
}
ul li {
  display: block;
  float: left;
  margin: 0;
  list-style-type: none;
  padding: 0;
}
ul li a {
  display: block;
  height: 100px;
  line-height: 100px;
  padding: 0 20px;
}
ul li ul {
  position: absolute;
  left: 0px;
  right: 0px;
  top: 100px;
  height: 0px;
  visibility: hidden;
  animation: hideDropdown 1s;
  animation-delay: 0.5s;
  animation-fill-mode: backwards;
}
ul li ul li {
  position: absolute;
  left: 50px;
  bottom: 0px;
  width: 200px;
  overflow: hidden;
  height: 100px;
}
ul li ul li a {
  display: block;
  height: 100px;
  background: red;
  padding: 0 20px;
  position: absolute;
  opacity: 0;
  transform: translate(0px, 100px);
  animation: hideDropdownItem 1s 0.2s;
  animation-fill-mode: backwards;
}
ul li ul li:first-child a {
  animation-delay: 0.4s;
}
ul li ul li:last-child {
  left: 250px;
}
ul li ul li:last-child a {
  animation-delay: 0.2s;
}
ul li:hover ul {
  animation: showDropdown 1s forwards;
  animation-delay: 0s;
}
ul li:hover ul li a {
  animation: showDropdownItem 1s forwards 0.2s;
}
ul li:hover ul li:last-child a {
  animation-delay: 0.4s;
}
@keyframes showDropdown {
  from {
    opacity: 0;
    height: 0;
    visibility: hidden;
  }
  to {
    height: 100px;
    opacity: 1;
    visibility: visible;
  }
}
@keyframes hideDropdown {
  from {
    height: 100px;
    opacity: 1;
    visibility: visible;
  }
  to {
    opacity: 0;
    height: 0;
    visibility: hidden;
  }
}
@keyframes showDropdownItem {
  from {
    opacity: 0;
    transform: translate(0px, 100px);
  }
  to {
    opacity: 1;
    transform: translate(0px, 0px);
  }
}
@keyframes hideDropdownItem {
  from {
    opacity: 1;
    transform: translate(0px, 0px);
  }
  to {
    opacity: 0;
    transform: translate(0px, 100px);
  }
}

<ul>
  <li>
    <a href="#">Dropdown</a>
    <ul>
      <li><a href="">First</a>
      </li>
      <li><a href="">second</a>
      </li>
    </ul>
  </li>
  <li><a href="">Not dropdown</a>
  </li>
</ul>

Note: Same as with first snippet, the above one also uses plain CSS with no prefixes. SCSS version with prefixes is available here.

But as mentioned earlier, this wouldn't prevent the animation from being visible on page load. The only way to stop that is by using JavaScript.

这篇关于如何播放用于悬停的反向关键帧动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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