今期我们又来做一些花里胡哨的特效,就是模仿 macOS 的 Dock 这个图标放大的效果:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2Pml2ZucjY0gDOjFGN4UWNjJmMhZTNiJDOxMGN1cDZiBjN0UzYvw1M1YTM3QTNtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.gif)
01.gif
如果是单纯的逐个图标放大,其实就没什么难度。不过我们的作风是,要做就做得够细致,当游标在同一个图标上左右移动时,都会影响到左边和右边的图标大小的,达到一个很连贯的效果,这个就是今次的难度所在。
好了,那我们就开始吧。
HTML 的部分
打开 CodePen 编辑器,在 HTML 的部分加入一些图标,在这里我会用 Emoji 表情符号来代表,加入一个
<ul>
列表的标签,
class
设定为
dock
,然后用
<li>
装着每一个表情符号,再在外面套上一层
<div>
,class 是
glass
。
02.png
CSS 的部分
然后是 CSS 的部分,加入
html
选择器,把基础的文字大小设定为
15px
。加入
body
选择器,将
margin
和
padding
设定为
,
display
设定为
flex
,宽度设定为
100%
,
min-height
最小的高度设定为
100vh
,
overflow
设定为
hidden
。
然后要把它定位到页面的下方,
align-items
设定为
flex-end
。
03.png
加入
.glass
选择器,宽度设定为
100%
,高度设定为
8rem
,然后背景颜色设定为浅灰色,
display
设定为
flex
,
justify-content
设定为
center
。
加入
.dock
选择器,将图标居中以及横向排列,
list-style
列表的样式设定为
none
,
margin
和
padding
设定为
,
display
设定为
flex
,
justify-content
和
align-items
设定为
center
。
再设定图标的样式,加入
.dock li
选择器,由于这里用的是表情符号,所以可以通过设定
font-size
来调整它的大小,
font-size
设定为
6rem
。然后加入一些
padding
,左右设定为
0.5rem
,
cursor
游标的样式设定为
default
即是预设的箭头。
04.png
好了,样式的部分都差不多了,接下来就是实现特效的部分。
动画的原理
首先我们了解一下这个效果的原理,举例我们将游标移动到第四个图标上的时候,它会放大。除此之外,在它旁边的第三个和第五个图标都会稍为放大一点,而当游标的位置比较靠左的时候,第三个就会比第五个放大一点,反之亦然。
所以我们就要知道游标在某一个图标上的时候,是在左边,中间还是右边的位置。
JavaScript 的部分
来到 JavaScript 的部分,先用
querySelectorAll()
把所有
.dock li
获取回来。然后通过回圈,为每一个
li
加入
mousemove
事件监听器。
定义一个变量
item
,赋值为
e.target
,因为稍后会多次引用到。然后要知道图标所在的
li
容器的宽度,定义变量
itemRect
,赋值为
item.getBoundingClientRect()
。
然后就是计算游标在图标上的位置,定义变量
offset
,赋值为
e.clientX
减去
itemRect.left
,由于它可能是负值,所以套上
Math.abs()
,再除以
itemRect.width
。
现在当游标移到图标左边的时候,
offset
会趋近于
,移到右边的时候,
offset
会趋近于
1
。
05.png
有了这个值,我们就可以计算图标的放大比例了。定义两个变量,分别是
prev
和
next
,通过
previousElementSibling
以及
nextElementSibling
获取当前游标所在的图标,前一个以及后一个的
li
元素。
再定义一个变量
scale
,假如我想图标放到最大是
1.6
倍,这里就赋值为
0.6
。
然后就计算放大的比率,并且写入到对应元素的 CSS 变量之中。在设定
prev
之前,要先判断一下是否能够获取到到它,因为当游标在第一个图标上的时候,
prev
就会是
null
。然后通过
setProperty()
,将放大的比率设定到 CSS 的变量里面,我会设定为
1
加上
scale
乘以
Math.abs(offset \- 1)
,
offset \- 1
是因为现在正在设定左边的元素,所以
offset
的值要相反,即是将
至
1
改为
1
至
。
然后运用相同的逻辑设定右边元素的放大比率,不同的是,这里的
offset
直接使用就可以了,而对于当前的图标呢,就直接设定为
1 + scale
就是最大值了。
06.png
定义一个用于重置
--scale
的函式,名为
resetScale()
,把所有
li
的
--scale
重置为
1
。
07.png
总共有两处位置需要执行这个函式的,分别是在
mousemove
事件里面,以及当游标离开这个 Dock 的时候。新增
mouseleave
事件监听器,并且执行
resetScale()
,就可以了。
08.png
09.png
通过开发者工具,看一下
--scale
的变化:
10.gif
在游标移动的过程当中,会将超出范围的
li
的
--scale
重置为
1
,以及在游标离开 Dock 的时候,所有
li
的
--scale
都重置为
1
。
最后一步
好了,来到这里,就差一步就完成了。
回到 CSS 的部份,将文字大小的设定值更改为
6rem
乘以
var(--scale)
,因为涉及到运算,所以套上一层
calc()
。
在
.dock
选择器内初始化
--scale
为
1
。测试一下:
11.gif
放大效果就达到了,不过定位有点问题。这个也不难解决,将
position
设定为
relative
。然后计算一下
top
相对于图标放大后的位移就可以了。再增加一点点的
transition
动画过渡的设定。
12.png
我们顺便将点击图标然后载入中的效果都做出来吧,如果你有兴趣的话,暂停一下,试试自己实现一下。
这里也很简单,定义一个叫做
loading
的动画设定,通过
translateY()
将它上下移动,然后加入
.dock li.loading
选择器,即是当
li
有
loading
这个 class 的时候,执行这个动画,并且无限次重覆。
13.png
再到 JavaScript 的部分,加入针对
li
的点击事件监听器,然后为目标的元素加上
loading
这个
class
就可以了。
14.png
我们来看看这个案例的完成效果
Final.gif
以上,就是今期要介绍的全部内容。
案例源代码请在公号回复关键字 macOS Dock 效果获取
转自:CodingStartup起码课
https://juejin.cn/post/6942325271349592100