今天来实现一个有趣的按钮效果,鼠标悬停在按钮上的时候会有水纹跟随,点击的时候会有一个水纹扩散的效果。当然,这样的动画效果你也可以添加到整个页面或者其他具体的元素上,实现的逻辑都是一样的。
在线体验
码上掘金
codePen
代码实现
html部分
html 部分比较简单,外部是一个 button 按钮,然后在按钮内部加上一个 div 作为水纹容器。
<div class="container">
<button class="water-ripple-btn" id="rippleBtn">
<span>水纹按钮</span>
<div class="ripple-container" id="rippleContainer"></div>
</button>
</div>
css部分
按钮基本样式
给按钮加上一点简单的样式。,半透明渐变背景(linear-gradient)搭配毛玻璃效果(backdrop-filter) 。
.water-ripple-btn {
position: relative;
width: 220px;
height: 70px;
border: none;
border-radius: 10px;
font-size: 1.2rem;
font-weight: 600;
color: white;
background: linear-gradient(135deg, rgba(59, 130, 246, 0.3), rgba(236, 72, 153, 0.3));
backdrop-filter: blur(10px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
cursor: pointer;
overflow: hidden;
transition: all 0.3s ease;
}
.water-ripple-btn:hover {
transform: translateY(-3px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3);
}
悬停水纹样式
.hover-ripple {
width: 30px;
height: 30px;
background: radial-gradient(circle, rgba(255, 255, 255, 0.25) 0%, rgba(255, 255, 255, 0) 70%);
box-shadow: 0 0 15px rgba(255, 255, 255, 0.3);
transition: transform 500ms ease-out, opacity 500ms ease-out;
}
较低的透明度(0.25)和较小的阴影(0 0 15px),避免干扰主体按钮。
水纹扩散样式
.click-ripple {
background: radial-gradient(circle, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0) 70%);
box-shadow: 0 0 25px rgba(255, 255, 255, 0.4);
transform: translate(-50%, -50%) scale(0);
opacity: 0.4;
transition: transform 1800ms ease-out, opacity 1800ms ease-out;
}
通过 scale(0) 到 scale(1) 的变换,让水纹从点击点向四周扩散。
JavaScrip部分
创建悬停水纹
btn.addEventListener("mousemove", (e) => {
if (!isHovering) {
isHovering = true;
hoverRipple = document.createElement("div");
hoverRipple.className = "hover-ripple";
rippleContainer.appendChild(hoverRipple);
}
const rect = btn.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 更新悬停水纹位置
hoverRipple.style.left = `${x}px`;
hoverRipple.style.top = `${y}px`;
hoverRipple.style.opacity = "1";
hoverRipple.style.transform = `translate(-50%, -50%) scale(1)`;
});
监听按钮内鼠标移动事件,在首次移动的时候创建悬停水纹元素,计算当前鼠标所在按钮中的相对位置,实时更新悬停水纹位置,保持水纹跟随鼠标。
隐藏悬停水纹
btn.addEventListener("mouseleave", () => {
if (hoverRipple) {
hoverRipple.style.opacity = "0";
hoverRipple.style.transform = `translate(-50%, -50%) scale(0)`;
setTimeout(() => {
rippleContainer.removeChild(hoverRipple);
hoverRipple = null;
isHovering = false;
}, 500);
}
});
监听鼠标离开按钮的事件,在鼠标离开按钮的时候通过 scale(0) 和 opacity: 0 触发水纹缩小并透明化的动画,在动画结束之后移除元素。
点击水纹扩散
btn.addEventListener("click", (e) => {
const rect = btn.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const widthDif = Math.max(rect.width - x, x);
const heightDif = Math.max(rect.height - y, y);
const radius = Math.max(widthDif, heightDif);
const createWaterPatterns = () => {
const ripple = document.createElement("div");
ripple.className = "click-ripple";
ripple.style.left = `${x}px`;
ripple.style.top = `${y}px`;
ripple.style.width = `${radius * 2 + 20}px`;
ripple.style.height = `${radius * 2 + 20}px`;
rippleContainer.appendChild(ripple);
setTimeout(() => {
ripple.style.transform = `translate(-50%, -50%) scale(1)`;
}, 100);
setTimeout(() => {
ripple.remove();
}, 1800);
};
createWaterPatterns();
});
监听按钮的点击事件,先计算鼠标到按钮四边的最大距离,以最大距离为扩散水纹的最大半径,确保水纹完成扩散到按钮外部再消失。计算当前鼠标所在按钮中的相对位置,在鼠标点击位置生成一个水纹元素,通过 scale(1) 触发水纹的扩散动画效果。
源码
gitee
github
- 🌟 觉得有帮助的可以点个 star~
- 🖊 有什么问题或错误可以指出,欢迎 pr~
- 📬 有什么想要实现的功能或想法可以联系我~
公众号
关注公众号『 前端也能这么有趣 』,获取更多有趣内容。
发送 加群 还可以加入群聊,一起来学习(摸鱼)吧~
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。