CSS3:动画精灵 + 鼠标悬停过渡

4
我正在学习CSS3动画和过渡,希望您能谅解我的无知。 以下是我尝试做的简化版:
  • 我有一个球通过CSS3关键帧“脉动”无限。
  • 当我将鼠标悬停在球上时,我希望球变大并保持这样的状态。
  • 当我将鼠标移开时,我希望球再次变小并继续“脉动”(所有过渡都需要平滑进行)。
以下是我使用CSS3动画和过渡的尝试(目前在Chrome上测试,因此使用了webkit前缀):
@-webkit-keyframes pulsate {
    from {
        -webkit-transform: scale(0.7);
    }    
    to {
        -webkit-transform: scale(0.8);
    }
}

.ball {
    background: blue;
    width: 100px;
    height: 100px;
    border-radius: 50%;
    transition: all 1s;

    -webkit-transform: scale(0.7);
    -webkit-transform-origin: center center; 

    -webkit-animation-duration: 800ms;
    -webkit-animation-name: pulsate;
    -webkit-animation-iteration-count: infinite;
    -webkit-animation-direction: alternate;
    -webkit-animation-timing-function: ease-in-out;
}

.ball:hover {
    -webkit-transform: scale(2);
    -webkit-animation-play-state: paused; /* transition works but gets reset at the end*/
    /*-webkit-animation: 0;*/ /* transition works only one time, and no smooth transition on mouse out */
}

jsFiddle演示

结果非常接近,但是一旦球在悬停时扩展完成,它突然又变小了(不知道为什么)。我还尝试过通过-webkit-animation: 0;禁用动画而不是暂停它,但效果也不好。

我尝试了另一种方法,只使用关键帧(没有过渡),并尝试在悬停时调用不同的关键帧集:

@-webkit-keyframes pulsate {
    from {
        -webkit-transform: scale(0.7);
    }    
    to {
        -webkit-transform: scale(0.8);
    }
}

@-webkit-keyframes expand {
    to {
        -webkit-transform: scale(2);
    }
}

@-webkit-keyframes shrink {
    to {
        -webkit-transform: scale(0.7);
    }
}

.ball {
    background: blue;
    width: 100px;
    height: 100px;
    border-radius: 50%;
    transition: all 2s;

    -webkit-transform: scale(0.7);
    -webkit-transform-origin: center center; 

    -webkit-animation-duration: 800ms, 800ms;
    -webkit-animation-name: shrink, pulsate;
    -webkit-animation-iteration-count: 1, infinite;
    -webkit-animation-direction: normal, alternate;
    -webkit-animation-timing-function: ease-in-out, ease-in-out;
}

.ball:hover {
    -webkit-animation-name: expand;
    -webkit-animation-iteration-count: 1;
    -webkit-animation-direction: normal;
    -webkit-animation-fill-mode: forwards;    
}

jsFiddle演示

当鼠标停留在球上时,球保持大的状态,但是当鼠标移开球时,仍然没有平滑的过渡效果。我希望它播放缩小动画,但它没有。

我是否遗漏了什么或者这种效果纯CSS实现目前不可能?

// 相关主题,但对我无效: 停止动画并开始悬停过渡


1
在你的第一个fiddle中,如果你在过渡中添加一个轻微的延迟,它将始终在悬停时进行过渡(不仅仅是第一次):transition: all 1s 0.01; - http://jsfiddle.net/danield770/ntTUt/1/ - Danield
有意思!你能解释一下它为什么起作用吗?我仍然需要在它跳动时从任意状态开始过渡,而不是像现在这样从 scale(0.7) 开始,并在鼠标移出时平稳地过渡回去。 - Dmitry Pashkevich
2个回答

3

你需要添加一个动画延迟来允许过渡完成,因为在动画开始时它会恢复到scale(.7)更新的jsFiddle

-webkit-animation-delay:1s;

编辑

我意识到我在这里发布的答案并不完全正确。确实,延迟使得从大变小的过渡有动画效果,但如果您将鼠标悬停在脉动球上时,它会跳回到其扩展的0.7值,然后再缩放到大尺寸。

更新的演示

我想出了一个解决方法,只需要使用一些JavaScript代码即可修复,基于此文章。您需要稍微更改CSS,但在结果中几乎不太明显。这是更新后的代码:

/* CSS */
body {margin: 100px;}

@-webkit-keyframes pulsate {
    0% {
        -webkit-transform: scale(0.7);
    }    
    50% {
        -webkit-transform: scale(0.8);
    }
    100% {
        -webkit-transform: scale(0.7);
    }
}

.ball {
    background: blue;
    width: 100px;
    height: 100px;
    border-radius: 50%;    
    -webkit-transform: scale(0.7);
    -webkit-transform-origin: center center; 
    transition: all 1s;
}
.ball.animated {
  -webkit-animation-duration: 1600ms; 
  -webkit-animation-name: pulsate;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-direction: alternate;
  -webkit-animation-timing-function: ease-in-out;
}

/* Javascript */
var ball = document.getElementsByClassName('ball')[0],
    pfx = ["webkit", "moz", "MS", "o", ""],
    hovered = false;

function AnimationListener() {
    if(hovered)
    { 
      ball.classList.remove('animated');     
      ball.style.webkitTransform = 'scale(2)';
      ball.style.transform = 'scale(2)';
    }
}

function TransitionListener() {
  if(!hovered)
  {
    ball.classList.add('animated');
  }
}

function PrefixedEvent(element, type, callback) {
    for (var p = 0; p < pfx.length; p++) {
        if (!pfx[p]) type = type.toLowerCase();
        element.addEventListener(pfx[p]+type, callback, false);
    }
}

PrefixedEvent(ball, "AnimationIteration", AnimationListener);

ball.onmouseover = function() {
  hovered = true;
}
ball.onmouseout = function() {
  hovered = false;
  PrefixedEvent(ball, "TransitionEnd", TransitionListener);
  ball.style.webkitTransform = 'scale(.7)';
  ball.style.transform = 'scale(.7)';  
}

太好了,我没有意识到,谢谢!只剩下一个小问题了 - 当鼠标悬停在球上时,是否可以使球从其当前状态开始扩展(而不是从初始状态开始)?设置“-webkit-animation-fill-mode:forwards;”没有帮助,因为我在悬停时禁用了动画。 - Dmitry Pashkevich
1
理论上,你可以让动画在过渡期间运行更长时间,但由于它们影响相同的变量(比例),所以你不能这样做。然后问题就变成了另一个问题,即获取关键帧的当前百分比并近似结果。这是可能的,但你必须使用JavaScript来实现。我曾经提出了一个问题,并尝试提供一个解决方案(使用稍微不同的动画),在这里SO上 - Zach Saucier
换句话说,在CSS3中,没有办法在保留状态的同时从一个关键帧序列切换到另一个关键帧序列。 - Dmitry Pashkevich
不使用JavaScript或更改不同的值,无法实现。 - Zach Saucier
还有什么其他问题我可以回答吗? - Zach Saucier
显示剩余2条评论

1

只需更新此CSS规则,我已经添加了“从”和“到”- 在展开和收缩中:

@-webkit-keyframes expand {
    from {
        -webkit-transform: scale(1);
    }    
    to {
        -webkit-transform: scale(2);
    }
}

@-webkit-keyframes shrink {
    from {
        -webkit-transform: scale(2);
    }    
    to {
        -webkit-transform: scale(1);
    }
}

谢谢,这看起来更好了。但是我不明白为什么需要显式指定 from。规范说如果省略 from,浏览器会使用当前计算出的样式作为起点。这是期望的行为,因为我可以在球完全扩展之前将鼠标移开,我不想在那里看到跳跃。 - Dmitry Pashkevich

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