实现思路概述
弹窗缺乏动态感的核心原因是没有过渡或动画效果,直接切换显示状态。我们可以给弹窗添加初始的缩放和透明度状态,再通过keyframes定义从初始状态到最终状态的弹性变化过程,当弹窗触发显示时执行该动画即可。

基础弹窗样式搭建
首先我们需要搭建一个基础的弹窗结构,包含弹窗容器和遮罩层,默认状态下弹窗隐藏,遮罩层也不可见。
<!-- 弹窗结构 -->
<div class="modal-mask" id="modalMask">
<div class="modal-container" id="modalContainer">
<h3>提示弹窗</h3>
<p>这是一段弹窗内容</p>
<button onclick="closeModal()">关闭弹窗</button>
</div>
</div>
<button onclick="openModal()">打开弹窗</button>
接着给弹窗和遮罩层添加基础样式,设置初始隐藏状态,这里先不添加动画相关属性。
/* 遮罩层样式 */
.modal-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: none;
justify-content: center;
align-items: center;
z-index: 1000;
}
/* 弹窗容器样式 */
.modal-container {
width: 400px;
padding: 24px;
background-color: #fff;
border-radius: 8px;
box-sizing: border-box;
}
/* 隐藏状态 */
.modal-mask.hide {
display: none;
}
定义弹性放大关键帧动画
我们需要用@keyframes定义动画过程,结合scale控制缩放大小,opacity控制透明度,模拟弹性效果。
/* 弹性放大动画定义 */
@keyframes elasticScale {
0% {
/* 初始状态:缩小到0.3倍,完全透明 */
transform: scale(0.3);
opacity: 0;
}
50% {
/* 中间状态:放大到1.05倍,完全不透明 */
transform: scale(1.05);
opacity: 1;
}
70% {
/* 回弹状态:缩小到0.98倍 */
transform: scale(0.98);
opacity: 1;
}
100% {
/* 最终状态:恢复到正常大小 */
transform: scale(1);
opacity: 1;
}
}
这里的关键帧设置了四个节点,0%是初始隐藏状态,50%超过正常大小产生弹性过冲效果,70%小幅回弹,100%回到正常状态,这样就能形成自然的弹性感。
弹窗触发逻辑实现
接下来需要给弹窗添加动画触发逻辑,打开弹窗时执行定义好的动画,同时显示遮罩层,关闭时移除动画并隐藏。
首先给弹窗容器添加动画相关样式:
/* 弹窗动画样式 */
.modal-container {
/* 其他原有样式不变 */
transform: scale(0.3);
opacity: 0;
}
/* 执行动画的类 */
.modal-container.animate {
animation: elasticScale 0.4s ease-out forwards;
}
然后编写js控制逻辑:
// 打开弹窗
function openModal() {
const mask = document.getElementById('modalMask');
const container = document.getElementById('modalContainer');
// 先移除隐藏类,显示遮罩层
mask.classList.remove('hide');
// 触发重排,确保初始样式生效
container.offsetHeight;
// 添加动画类,执行弹性动画
container.classList.add('animate');
}
// 关闭弹窗
function closeModal() {
const mask = document.getElementById('modalMask');
const container = document.getElementById('modalContainer');
// 移除动画类
container.classList.remove('animate');
// 添加隐藏类,隐藏遮罩层
mask.classList.add('hide');
}
参数调整说明
你可以根据实际需求调整动画参数:
- 修改
@keyframes中50%节点的scale值,调整弹性过冲的幅度,值越大过冲越明显 - 修改
animation的0.4s参数,调整动画总时长,时长越长动画越慢 - 可以新增更多关键帧节点,让弹性效果更细腻
完整代码示例
以下是所有代码整合后的完整示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>css弹窗弹性动画示例</title>
<style>
.modal-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: none;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-mask.hide {
display: none;
}
.modal-container {
width: 400px;
padding: 24px;
background-color: #fff;
border-radius: 8px;
box-sizing: border-box;
transform: scale(0.3);
opacity: 0;
}
.modal-container.animate {
animation: elasticScale 0.4s ease-out forwards;
}
@keyframes elasticScale {
0% {
transform: scale(0.3);
opacity: 0;
}
50% {
transform: scale(1.05);
opacity: 1;
}
70% {
transform: scale(0.98);
opacity: 1;
}
100% {
transform: scale(1);
opacity: 1;
}
}
button {
margin-top: 16px;
padding: 8px 16px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="modal-mask hide" id="modalMask">
<div class="modal-container" id="modalContainer">
<h3>提示弹窗</h3>
<p>这是一段弹窗内容</p>
<button onclick="closeModal()">关闭弹窗</button>
</div>
</div>
<button onclick="openModal()">打开弹窗</button>
<script>
function openModal() {
const mask = document.getElementById('modalMask');
const container = document.getElementById('modalContainer');
mask.classList.remove('hide');
container.offsetHeight;
container.classList.add('animate');
}
function closeModal() {
const mask = document.getElementById('modalMask');
const container = document.getElementById('modalContainer');
container.classList.remove('animate');
mask.classList.add('hide');
}
</script>
</body>
</html>