最近看阿里云首页上的鼠标悬浮动效图标很好看,比较好奇怎么做的。
然后自己空闲时间实现了一个,现将步骤列出如下(想直接看代码的拉到最后):
1、
首先你需要这样一张图,像展开的gif一样,把所有的动画帧竖列排开拼成一张长图,就比如这个:
图源:阿里云首页
这张图片的尺寸很有讲究,示例的这张长图的每一张小图都是64px * 64px的,一共20张,整体是64px * 1280px的大小,注意这几个数值,后续都会用到。
2、
创建一个div,把图片设置为其背景图,div大小与单独的一张图片大小完全一致,初始时竖直方向上位于第一张图片的位置。
<div id="anime_icon" class="anime-icon"></div>
.anime-icon{
width: 64px;/*这个尺寸不能乱动,按照图片的尺寸来*/
height: 64px;
cursor: pointer;
background-image: url('1.png');
background-size: 100%; /*使图片和div的大小匹配*/
background-position-y: 0; /*竖直方向上位于第一张图片的位置*/
}
3、
再之后需要两个animation,一个负责鼠标移入时的动画,一个负责鼠标移出时的动画,内容很简单,就是对图片的竖直方向位置进行修改,即background-position-y的值
@keyframes mouse-in{
/*鼠标移入时从第一张移动到最后一张*/
from{
background-position-y: 0;
}
to{
background-position-y: -1280px;/*1280px就是图片的总长度,即64px 20张*/
}
}
@keyframes mouse-out{
/*鼠标移出时从最后一张移动回第一张*/
from{
background-position-y: -1280px;
}
to{
background-position-y: 0;
}
}
4、
最关键的一步来了,把动画绑定到类上,但是此时不能直接把mouse-out动画丢进anime-icon类里,因为这样会导致页面加载的时候就自动播放了一次从”最后一张图片到第一张图片“的动画,所以这里需要借助jquery,当触发了hover事件的时候,把mouse-out-class类丢上去。具体如下:
.anime-icon:hover{
/*hover时用0.5s执行mouse-in动画*/
animation: mouse-in .5s;
/*这一句极其重要,将mouse-in拆成20个步骤执行(还记得我们那张长图总共有多少张小图吗)*/
animation-timing-function:steps(20);
/*动画执行结束后,停在最后一帧上*/
animation-fill-mode:forwards;
}
.mouse-out-class{
/*0.5s执行移出动画*/
animation: mouse-out .5s;
/*移出动画依然分成20步骤*/
animation-timing-function:steps(20);
/*动画结束时停在最后一帧*/
animation-fill-mode:forwards;
}
然后在页面加载完成后,把mouse-out-class添加到div上即可:
$("#anime_icon").hover(function(){
$(this).addClass('mouse-out-class');
})
注意上面这种添加的方式是非常常见的,但是hover函数有个细节:只定义一个function的时候,mouseover和mouseout都会去执行这个方法,等于是addClass在每次hover的时候都会执行两次。而我们又不能在mouseout的function里删除mouse-out-class,动画会失效。所以对于强迫症来说,下面的方法细节上会更好:
$("#anime_icon").one('mouseover', function(){
$(this).addClass('mouse-out-class');
})
one方法只会在mouseover的时候执行一次,以后不再执行。one后面的第一个参数只能是mouseover而不能是hover,这里就涉及另一个细节:hover严格来说不算是个事件,它是mouseover和mouseout的一个合体,one函数第一个参数只能接受事件。
补充:
- 其实我一直想找不使用jquery参与的实现方式,但是问题就卡在了页面加载的时候会自动执行一次mouse-out动画这里,如果能有办法使这个动画在页面加载时不执行,hover以后再生效就完美了。但目前搜索到的方案都不是很满意。如果有好方法也感谢在下面评论。
- 动效尺寸的放缩由于div的尺寸不能乱改我能想到的估计就是scale了,没深入研究,不排除有别的方法可以改变生成的动效大小,也就是64px的小图,最后动效图标不是64px的,而是想要的任意尺寸。(或许同时修改width、height、background-size能行?不知道,懒得试。)
- 长图片不一定要求竖直排列,水平排列也行,无非就是改background-position-x。但是无论竖直还是水平,不能换行。
- div不需要overflow,因为长图是背景图,不是div的内容物。
- 不止阿里云,其实包括腾讯云首页上的那些动效,都是这么实现的(当然人家不一定用jquery,是有自己的框架和组件的)。
至此,想要的动效就实现完了。
最后提供一下完整代码,其中1.png就是上面的那张长图,jquery文件你自己去找好啦。
<html>
<header>
<script src="jquery.min.js"></script>
<style>
@keyframes mouse-in{
from{
background-position-y: 0;
}
to{
background-position-y: -1280px;
}
}
@keyframes mouse-out{
from{
background-position-y: -1280px;
}
to{
background-position-y: 0;
}
}
.anime-icon{
width: 64px;
height: 64px;
cursor: pointer;
background-image: url('1.png');
background-size: 100%;
background-position-y: 0;
}
.anime-icon:hover{
animation: mouse-in .5s;
animation-timing-function:steps(20);
animation-fill-mode:forwards;
}
.mouse-out-class{
animation: mouse-out .5s;
animation-timing-function:steps(20);
animation-fill-mode:forwards;
}
</style>
</header>
<body>
<div id="anime_icon" class="anime-icon"></div>
<script>
$("#anime_icon").one('mouseover', function(){
$(this).addClass('mouse-out-class');
})
// $("#anime_icon").hover(function(){
// $(this).addClass('mouse-out-class');
// })
</script>
</body>
</html>