Material Design的水滴动画按钮是很多项目中常用的交互效果,点击按钮时会出现从点击位置扩散的涟漪动画,视觉反馈清晰。其实不需要JavaScript参与,仅用纯CSS就能完整实现这个效果,核心是利用伪元素和CSS动画属性。

实现原理说明
整个效果的实现逻辑分为三个部分:首先是按钮的基础样式设置,需要开启相对定位,同时隐藏溢出内容,避免涟漪动画扩散到按钮外部;其次是使用::after伪元素作为涟漪的载体,默认状态设为透明且缩放为0;最后是监听按钮的点击状态,在激活时触发伪元素的缩放和透明度变化动画,形成扩散效果。
基础按钮样式设置
先定义按钮的基础外观,这里以常见的圆角按钮为例,代码如下:
/* 按钮基础样式 */
.ripple-btn {
position: relative; /* 为伪元素提供定位基准 */
overflow: hidden; /* 隐藏超出按钮范围的涟漪 */
padding: 12px 24px;
border: none;
border-radius: 4px;
background-color: #2196F3; /* Material Design主蓝色 */
color: #fff;
font-size: 16px;
cursor: pointer;
outline: none;
user-select: none; /* 避免选中按钮文字 */
}
涟漪动画核心实现
接下来通过::after伪元素实现涟漪效果,核心是利用transform: scale()控制大小变化,opacity控制透明度变化,配合transition实现平滑过渡:
/* 涟漪伪元素样式 */
.ripple-btn::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.3); /* 浅白色涟漪 */
border-radius: 50%;
transform: translate(-50%, -50%) scale(0); /* 初始缩放为0,居中定位 */
opacity: 0;
transition: transform 0.4s ease, opacity 0.4s ease; /* 动画过渡配置 */
pointer-events: none; /* 避免伪元素拦截点击事件 */
}
/* 点击激活时的动画状态 */
.ripple-btn:active::after {
transform: translate(-50%, -50%) scale(2); /* 放大到按钮的2倍 */
opacity: 1; /* 完全显示 */
}
适配点击位置的优化方案
上面的基础版本涟漪始终从按钮中心扩散,要模拟真实点击位置扩散的效果,需要通过CSS变量动态设置伪元素的位置,代码如下:
/* 优化后按钮样式,支持动态点击位置 */
.ripple-btn {
position: relative;
overflow: hidden;
padding: 12px 24px;
border: none;
border-radius: 4px;
background-color: #2196F3;
color: #fff;
font-size: 16px;
cursor: pointer;
outline: none;
user-select: none;
/* 定义CSS变量存储点击位置,默认居中 */
--ripple-x: 50%;
--ripple-y: 50%;
}
/* 优化后的伪元素,使用CSS变量定位 */
.ripple-btn::after {
content: '';
position: absolute;
top: var(--ripple-y);
left: var(--ripple-x);
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.3);
border-radius: 50%;
transform: translate(-50%, -50%) scale(0);
opacity: 0;
transition: transform 0.4s ease, opacity 0.4s ease;
pointer-events: none;
}
.ripple-btn:active::after {
transform: translate(-50%, -50%) scale(2);
opacity: 1;
}
虽然纯CSS无法直接获取点击坐标,但如果是需要适配点击位置的项目,可以配合极少量的JS设置CSS变量,不过核心动画仍然由CSS完成,这里提供配套的JS代码参考:
// 仅用于设置点击位置的JS代码,动画本身由CSS实现
document.querySelectorAll('.ripple-btn').forEach(btn => {
btn.addEventListener('click', function(e) {
// 计算点击位置相对于按钮的坐标
const x = e.pageX - this.offsetLeft;
const y = e.pageY - this.offsetTop;
// 设置CSS变量
this.style.setProperty('--ripple-x', x + 'px');
this.style.setProperty('--ripple-y', y + 'px');
});
});
效果适配与注意事项
- 按钮如果是圆形样式,只需要把
border-radius设置为50%,涟漪效果会自动适配圆形轮廓 - 如果按钮有背景图或者渐变背景,需要调整
::after伪元素的背景色透明度,避免遮挡原有内容 - 可以通过调整
transition的时长和缓动函数,修改涟漪扩散的速度和节奏,适配不同的设计需求 - 如果需要涟漪动画结束后自动重置,不需要额外处理,因为
:active状态结束后,伪元素会自动回到初始状态
完整示例代码
以下是包含HTML和CSS的完整可运行示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Material Design水滴动画按钮</title>
<style>
.ripple-btn {
position: relative;
overflow: hidden;
padding: 12px 24px;
border: none;
border-radius: 4px;
background-color: #2196F3;
color: #fff;
font-size: 16px;
cursor: pointer;
outline: none;
user-select: none;
--ripple-x: 50%;
--ripple-y: 50%;
margin: 20px;
}
.ripple-btn::after {
content: '';
position: absolute;
top: var(--ripple-y);
left: var(--ripple-x);
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.3);
border-radius: 50%;
transform: translate(-50%, -50%) scale(0);
opacity: 0;
transition: transform 0.4s ease, opacity 0.4s ease;
pointer-events: none;
}
.ripple-btn:active::after {
transform: translate(-50%, -50%) scale(2);
opacity: 1;
}
.round-btn {
border-radius: 50%;
width: 60px;
height: 60px;
padding: 0;
}
</style>
</head>
<body>
<button class="ripple-btn">普通按钮</button>
<button class="ripple-btn round-btn">圆形按钮</button>
<script>
document.querySelectorAll('.ripple-btn').forEach(btn => {
btn.addEventListener('click', function(e) {
const x = e.pageX - this.offsetLeft;
const y = e.pageY - this.offsetTop;
this.style.setProperty('--ripple-x', x + 'px');
this.style.setProperty('--ripple-y', y + 'px');
});
});
</script>
</body>
</html>
Material_Design水滴动画按钮css动画伪元素transition修改时间:2026-07-09 01:00:39