前言
最近使用Mac 的时候,突发奇想想研究一下Mac 程序坞的滑动效果。结果发现简单的HTML + CSS + JS 就可以实现,于是便有了这篇文章。
实现效果
话不多说,我们先来看看实现效果
实现过程
设计思路
- HTML 部分:
基础的HTML 结构- CSS 部分:
给每个应用图标(这里用带背景颜色的盒子来表示)设置一个CSS 变量--i
,并通过--i
来设置图标的宽高,这样在--i
变化的时候,就可以实现应用图标的放大和缩小,配合JS 代码从而实现缩放效果- JS 部分:
鼠标在程序坞内移动时,使用函数曲线进行计算,动态得到每个应用图标的--i
值
HTML 和CSS部分
HTML 和CSS 部分相对来说较为简单,需要注意的是图标之间的间隔不能通过margin
来设置,而是使用了div
盒子来充当间隔。
并且,通过css 变量--i
来设置盒子的大小,通过js 代码来控制--i
的值,这样便可控制盒子缩放,HTML 和CSS 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mac Dock</title>
<style>
html, body{
height: 99%;
}
.content{
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: end;
background-color: rgba(0, 0, 0, .8);
.menu{
margin-bottom: 20px;
padding: 12px 15px;
height: 40px;
display: flex;
justify-content: center;
align-items: end;
border-radius: 12px;
background-color: rgba(255, 255, 255, .4);
backdrop-filter: blur(20px);
--webkit-backdrop-filter: blur(20px);
.menu-item{
--i: 1;
border-radius: 10px;
width: calc(40px * var(--i));
height: calc(40px * var(--i));
margin-bottom: calc(var(--i) * 15px - 15px);
background-color: rgb(34, 199, 158);
}
.gap{
--i: 1;
width: calc(15px * var(--i));
}
}
}
</style>
</head>
<body>
<div class="content">
<div id="dock" class="menu">
<div class="menu-item"></div>
<div class="gap"></div>
<div class="menu-item"></div>
<div class="gap"></div>
<div class="menu-item"></div>
<div class="gap"></div>
<div class="menu-item"></div>
<div class="gap"></div>
<div class="menu-item"></div>
<div class="gap"></div>
<div class="menu-item"></div>
<div class="gap"></div>
<div class="menu-item"></div>
<div class="gap"></div>
<div class="menu-item"></div>
<div class="gap"></div>
<div class="menu-item"></div>
<div class="gap"></div>
<div class="menu-item"></div>
</div>
</div>
</body>
</html>
JS 部分
当我们鼠标在程序坞上移动的时候,可以看到一个起伏的效果。起伏是一个范围,并且鼠标所在为中心点,图标放大倍数最大,向两边依次递减。
基于这个起伏的形状,可以联想到正弦函数sin 函数在[0 - π]
区间内的函数曲线,我们可以通过这段函数曲线,来计算放大倍数。鼠标所在位置的值为π/2
,也是sin 函数的最大值,向两边依次递减且对称。
首先我们需要给定一个缩放范围range = 300
,监听程序坞的mousemove
事件,使用createCurve 函数
来计算以当前鼠标位置为中心,range
范围内每个元素的放大倍数,并通过layout 函数
来对每个元素css 中的变量--i
进行修改,从而实现缩放效果。js 代码如下所示:
const items = document.querySelector('.menu').children
const dock = document.querySelector('.menu')
const range = 300
const maxScale = 1.8
document.querySelector('.menu').addEventListener('mousemove', (e) => {
const curve = createCurve(range, e.clientX, 1, maxScale)
layout(curve)
const rect = dock.getBoundingClientRect()
const width = rect.right - rect.left
})
document.querySelector('.menu').addEventListener('mouseleave', (e) => {
layout(() => 1)
dock.style.setProperty('width', 'fit-content')
})
document.querySelector('.menu').addEventListener('mouseenter', (e) => {
const rect = dock.getBoundingClientRect()
const width = rect.right - rect.left + 80
dock.style.setProperty('width', width + 'px')
})
function createCurve(totalDis, topX, minY, maxY){
return function curve(x) {
const beginX = topX - totalDis / 2
const endX = topX + totalDis / 2
if (x < beginX || x > endX) return minY
const yDis = maxY - minY
return (baseCurve((x - beginX) / totalDis) * yDis + minY)
}
}
function baseCurve(x) {
if(x < 0 || x > 1) return 1
return Math.sin(x * Math.PI)
}
function layout(curve) {
Array.from(items).forEach(item => {
const rect = item.getBoundingClientRect()
const x = rect.left + rect.width / 2
const scale = curve(x)
item.style.setProperty('--i', scale)
})
}
结尾
以上就是Mac 程序坞缩放效果的实现过程了,希望对你有些参考作用。