✨ 前言
源码地址:leixq1024/FrontEndSnippetHub: ✨html+css+js的前端特效合集
本次灵感来源:codepen.io/zorgos/pen/...
这个系列主要分享一些用css
+html
+js
制作的前端特效或动画的代码实现思路和解析。如果对你有帮助请给仓库点一个✨
🎬 效果演示

🧰 前期准备
这里我准备了两个图片一个是地图,一个是火把gif,并且创建了index.html
、style.css
、index.js
三个文件

🗺️ 初始化场景
index.html
html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>地图聚光灯</title>
<!-- <link rel="stylesheet" href="style.css" /> -->
</head>
<body>
<div class="map">
<!-- 黑色遮罩 -->
<div class="mask" id="mask"></div>
<!-- 火把gif,随光圈移动 -->
<img id="torch" src="./img/torch.gif" alt="火把" />
</div>
<script src="index.js"></script>
</body>
</html>
刚开始没有设置样式效果就如下

🎨 编写样式
先把地图放上去
css
html,
body {
position: relative;
width: 100%;
height: 100%;
margin: 0;
cursor: none;
}
/* 地图 */
.map {
position: relative;
width: 100vw;
height: 100vh;
background: url('./img/map.png') no-repeat;
background-size: 100% 100%;
}
效果如下

接下来做一个黑色的背景,并且用mask-image
做一个蒙版
css
.mask {
position: absolute;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 1);
mask-image: radial-gradient(
circle var(--r, 110px) at var(--x, 50%) var(--y, 50%),
transparent 0%,
transparent 50%,
black 100%
);
transition: -webkit-mask-position 0.06s linear;
transition: mask-position 0.06s linear;
pointer-events: auto;
}
- 通过
mask-image
的径向渐变创建圆形透明区域 transparent 0%
到transparent 50%
:中心区域完全透明(显示底层内容)black 100%
:边缘黑色区域遮挡内容- 最终效果:黑色背景中有一个圆形"窗口"
其中transition: mask-position 0.06s linear;
中的mask-position
是指遮罩位置
,这样遮罩位置变化就会有一个线性的过渡
这里蒙版的一些值用css变量来控制,方便等下用js动态的更新蒙版的位置
效果如下

🔥 火把样式
css
/* 火把样式 */
#torch {
position: absolute;
width: 100px;
height: 100px;
pointer-events: none;
z-index: 10;
left: var(--x, 50%);
top: var(--y, 50%);
transform: translate(-50%, -50%);
}
效果如下

🖱️ 鼠标和滚轮事件
index.js
javascript
let radius = 110 // 光照半径
// 设置css变量
const setStyleVar = (el, key, val) => el && el.style.setProperty(key, val)
// 遮罩元素
const mask = document.getElementById('mask')
// 火把元素
const torch = document.getElementById('torch')
// 修改遮罩层光圈位置
const setPos = (clientX, clientY) => {
const { left, top } = mask.getBoundingClientRect()
setStyleVar(mask, '--x', clientX - left + 'px')
setStyleVar(mask, '--y', clientY - top + 'px')
// 火把居中显示在光圈圆心
setStyleVar(torch, '--x', clientX - left + 'px')
setStyleVar(torch, '--y', clientY - top + 'px')
}
// 鼠标移动时,更新遮罩层光圈位置
mask.addEventListener('mousemove', (e) => {
setPos(e.clientX, e.clientY)
})
// 滚轮滚动时,更新光照半径
mask.addEventListener('wheel', (e) => {
radius = Math.max(50, Math.min(200, radius + e.deltaY * 0.1))
setStyleVar(mask, '--r', radius + 'px')
})
let flickerTime = 0
// 遮罩层呼吸效果
const maskBreathe = () => {
flickerTime += 0.05
setStyleVar(mask, '--r', radius + Math.sin(flickerTime * 3) * 3 + 'px')
requestAnimationFrame(maskBreathe)
}
maskBreathe()
其中 setStyleVar(mask, '--r', radius + Math.sin(flickerTime * 3) * 3 + 'px')
是通过正弦函数拟火把的自然闪烁效果
🌟 最终效果
