【前端特效系列】css+js实现聚光灯效果

✨ 前言

源码地址:leixq1024/FrontEndSnippetHub: ✨html+css+js的前端特效合集

本次灵感来源:codepen.io/zorgos/pen/...

​ 这个系列主要分享一些用css+html+js制作的前端特效或动画的代码实现思路和解析。如果对你有帮助请给仓库点一个✨

🎬 效果演示

🧰 前期准备

​ 这里我准备了两个图片一个是地图,一个是火把gif,并且创建了index.htmlstyle.cssindex.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')是通过正弦函数拟火把的自然闪烁效果

🌟 最终效果

相关推荐
Mh5 小时前
鼠标跟随倾斜动效
前端·css·vue.js
幺风7 小时前
Claude Code 源码分析 — Tool/MCP/Skill 可扩展工具系统
前端·javascript·ai编程
ZC跨境爬虫7 小时前
3D 地球卫星轨道可视化平台开发 Day7(AI异步加速+卫星系列精简+AI Agent自动评论)
前端·人工智能·3d·html·json
ID_180079054737 小时前
淘宝 API 上货 / 商品搬家 业务场景实现 + JSON 返回示例
前端·javascript·json
M ? A8 小时前
Vue 动态组件在 React 中,VuReact 会如何实现?
前端·javascript·vue.js·经验分享·react.js·面试·vureact
ZC跨境爬虫9 小时前
3D 地球卫星轨道可视化平台开发 Day8(分步渲染200颗卫星+ 前端分页控制)
前端·python·3d·重构·html
竹林8189 小时前
RainbowKit快速集成多链钱包连接,我如何从“连不上”到“丝滑切换”
前端·javascript
No8g攻城狮10 小时前
【前端】Vue 中 const、var、let 的区别
前端·javascript·vue.js
fishmemory7sec10 小时前
Vue大屏自适应容器组件:v-scale-screen
前端·javascript·vue.js
饺子不吃醋10 小时前
Promise原理、手写与 async、await
前端·javascript