基础实现(最简单)
这是最直接的方法,适合快速理解和入门。

(图片来源网络,侵删)
HTML 结构
只需要一个容器来包裹所有水滴,这样水滴就可以相对于这个容器定位。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">水滴效果</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>在页面上移动鼠标试试看!</h1>
<p>水滴会跟随你的鼠标出现。</p>
<div id="ripple-container"></div>
<script src="script.js"></script>
</body>
</html>
CSS 样式
我们为水滴元素(.ripple)定义样式和动画。
/* body 和容器样式 */
body {
font-family: sans-serif;
background-color: #282c34;
color: white;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden; /* 防止页面滚动条出现 */
cursor: none; /* 可选:隐藏默认鼠标指针 */
}
#ripple-container {
position: fixed; /* 固定定位,覆盖整个视口 */
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none; /* 关键:让容器不拦截鼠标事件,事件可以穿透到下方 */
}
/* 水滴样式 */
.ripple {
position: absolute;
border-radius: 50%; /* 圆形 */
background-color: rgba(255, 255, 255, 0.7); /* 半透明白色 */
transform: scale(0); /* 初始状态为0大小 */
animation: ripple-animation 0.6s linear;
pointer-events: none; /* 水滴本身也不拦截事件 */
}
/* 定义水滴的扩散和消失动画 */
@keyframes ripple-animation {
to {
transform: scale(4); /* 放大到4倍 */
opacity: 0; /* 完全透明 */
}
}
JavaScript 逻辑
这是实现效果的核心,监听鼠标移动事件,创建水滴元素并应用动画。
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('ripple-container');
// 监听整个文档的鼠标移动事件
document.addEventListener('mousemove', (e) => {
// 1. 创建一个新的水滴元素
const ripple = document.createElement('div');
ripple.classList.add('ripple');
// 2. 设置水滴的初始位置(鼠标点击的位置)
// 使用 clientX 和 clientY 获取相对于视口的坐标
const size = 20; // 水滴的初始大小
ripple.style.width = `${size}px`;
ripple.style.height = `${size}px`;
// 计算水滴的中心点对准鼠标位置
ripple.style.left = `${e.clientX - size / 2}px`;
ripple.style.top = `${e.clientY - size / 2}px`;
// 3. 将水滴添加到容器中
container.appendChild(ripple);
// 4. 动画结束后移除水滴,防止DOM元素堆积
// 这一步对于性能至关重要!
ripple.addEventListener('animationend', () => {
ripple.remove();
});
});
});
进阶实现(点击触发,更炫酷)
这个版本模仿了很多现代网站的效果,水滴只在点击时产生,并且颜色可以随机,或者根据背景色变化。

(图片来源网络,侵删)
HTML 结构
和基础版本类似,只是提示文字变了。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">点击水滴效果</title>
<link rel="stylesheet" href="advanced-style.css">
</head>
<body>
<h1>点击页面任意位置!</h1>
<p>每次点击都会产生一个彩色水滴。</p>
<div id="ripple-container"></div>
<script src="advanced-script.js"></script>
</body>
</html>
CSS 样式
这里我们让水滴的颜色和大小随机,视觉效果更丰富。
/* body 和容器样式与基础版类似 */
body {
font-family: sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); /* 渐变背景 */
color: white;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
cursor: pointer; /* 提示用户可以点击 */
}
#ripple-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
/* 水滴样式,颜色和大小将由JS动态设置 */
.ripple {
position: absolute;
border-radius: 50%;
transform: scale(0);
animation: ripple-animation 0.6s ease-out;
pointer-events: none;
background: radial-gradient(circle, rgba(255,255,255,0.8) 0%, rgba(255,255,255,0) 70%);
}
@keyframes ripple-animation {
to {
transform: scale(10); /* 放大倍数可以更大 */
opacity: 0;
}
}
JavaScript 逻辑
修改为监听 click 事件,并动态生成随机的颜色和大小。
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('ripple-container');
// 监听整个文档的点击事件
document.addEventListener('click', (e) => {
const ripple = document.createElement('div');
ripple.classList.add('ripple');
// 随机大小 (20px 到 100px)
const size = Math.random() * 80 + 20;
ripple.style.width = `${size}px`;
ripple.style.height = `${size}px`;
// 随机颜色 (使用 HSL 色彩模式更容易生成鲜艳的颜色)
const hue = Math.floor(Math.random() * 360);
// 使用 HSL 颜色,并设置一定的透明度
ripple.style.background = `hsla(${hue}, 100%, 70%, 0.7)`;
// 计算位置,让水滴中心对准点击位置
ripple.style.left = `${e.clientX - size / 2}px`;
ripple.style.top = `${e.clientY - size / 2}px`;
container.appendChild(ripple);
// 动画结束后移除
ripple.addEventListener('animationend', () => {
ripple.remove();
});
});
});
关键点解析
-
pointer-events: none:这个CSS属性非常重要,它告诉浏览器这个元素不响应鼠标事件(如点击、悬停),这样,鼠标事件就能穿透水滴,继续传递到页面上的其他元素(如果有的话),或者在我们的例子中,就是传递到document上,从而保证每次点击或移动都能产生新的水滴。
(图片来源网络,侵删) -
animationend事件:在基础和进阶版本中,我们都监听了这个事件,动画结束后,我们手动调用element.remove()来删除DOM节点,如果不这样做,随着用户不断点击或移动,页面上会堆积成百上千个看不见的.ripple元素,严重影响浏览器性能,甚至可能导致页面卡死。 -
定位:我们使用
position: absolute和left/top来定位水滴,因为它的父容器#ripple-container是position: fixed,所以水滴是相对于整个视口进行定位的,而不是相对于页面上的其他内容。 -
性能优化:
- 移除DOM元素:如上所述,这是最关键的一步。
- 使用
requestAnimationFrame:对于非常频繁的鼠标移动事件(比如方案一),可以考虑使用requestAnimationFrame来节流,避免在短时间内创建过多水滴,但对于大多数情况,直接监听mousemove并配合animationend移除已经足够流畅。
| 特性 | 基础版 (鼠标移动) | 进阶版 (鼠标点击) |
|---|---|---|
| 触发事件 | mousemove |
click |
| 视觉效果 | 单一白色水滴 | 随机颜色和大小的水滴 |
| 适用场景 | 背景装饰,跟随光标 | 按钮点击反馈,页面交互 |
| 核心代码 | 在鼠标位置创建元素,动画后移除 | 在点击位置创建元素,动画后移除 |
你可以根据你的具体需求选择合适的方案,或者将两者结合,创造出更有趣的交互效果,希望这个详细的教程能帮助你实现想要的水滴效果!
