在移动端或桌面端的来电界面中,加入合适的动画可以让用户更快感知呼叫状态,也能让产品显得更生动。所谓来电动画,通常是指头像放大缩小、提示条滑入、铃铛摇晃等循环或一次性过渡效果。借助CSS原生能力,我们完全可以不依赖JavaScript定时器来达成这些表现。

一、理解CSS动画的基本构成
CSS动画主要由两部分组成:一是使用@keyframes定义动画的关键帧,二是通过animation属性将动画绑定到指定元素上并配置播放参数。关键帧描述了元素从起始状态到结束状态中间经过的样式变化,而animation属性则控制动画的时长、速度曲线、延迟、循环次数等。
与过渡(transition)不同,animation适合表达一段独立、可循环的复杂过程,例如来电时头像持续脉冲。transition更多用于用户交互触发的单次状态变化。在来电场景中,我们通常希望动画自动播放且不断重复,因此animation是更自然的选择。
1.1 关键帧的写法
下面是一段最基础的关键帧定义,它让元素从轻微缩小且半透明,变为正常大小且不透明,再回到初始状态,形成呼吸般的效果:
@keyframes callPulse {
0% {
transform: scale(0.9);
opacity: 0.7;
}
50% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(0.9);
opacity: 0.7;
}
}
这里的百分比表示动画时间进度,0%是开始,100%是结束。你可以定义任意多个节点,浏览器会在它们之间做平滑插值。注意所有变化都应尽量落在transform和opacity上,以减少布局重算。
1.2 绑定动画到元素
定义好关键帧后,需要在目标元素上用animation属性引用它:
.call-avatar {
width: 120px;
height: 120px;
border-radius: 50%;
animation: callPulse 1.2s ease-in-out infinite;
}
上面代码中,callPulse是动画名,1.2s是单次周期,ease-in-out是速度曲线,infinite表示无限循环。这样头像就会持续脉冲,很适合作为来电时的视觉焦点。
二、实现滑入与震动组合效果
真实来电界面往往不只一个动画。例如顶部提示条从上方滑入,同时铃铛图标左右摇晃。我们可以把多个动画分别应用到不同元素,或者用逗号分隔在同一个animation属性里叠加。
滑入效果适合用translateY配合opacity,从屏幕外进入视区;摇晃则可用rotate做小角度往复。两者都基于transform,不会引发重排,在低端机也较流畅。
2.1 滑入提示条
以下代码展示了一个来电横幅从顶部降下的进入动画:
@keyframes slideDown {
from {
transform: translateY(-100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.call-banner {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 80px;
background: #2c3e50;
color: #fff;
animation: slideDown 0.4s ease-out forwards;
}
这里使用了forwards填充模式,保证动画结束后停留在最后一帧,而不是闪回初始状态。由于只播放一次,没有设置infinite。
2.2 铃铛摇晃
铃铛或电话图标的摇晃可以用rotate实现,代码如下:
@keyframes ringShake {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(15deg); }
75% { transform: rotate(-15deg); }
}
.call-bell {
display: inline-block;
font-size: 32px;
animation: ringShake 0.6s ease-in-out infinite;
}
通过将动画周期设短一些,并加大角度,能明显增强急促感,符合来电提醒的紧张情绪。如果设备性能有限,可适当减小角度或延长周期。
三、用CSS变量增强可控性
在复杂项目中,我们常希望统一调节动画节奏。CSS自定义属性(变量)可以帮我们把时长、幅度提取出来,便于主题切换或A/B测试。
例如把脉冲周期和缩放下限定义为变量,在:root中集中管理,之后关键帧里通过var()引用。这样运营侧想临时放缓动画,只需改一处值。
3.1 定义变量与引用
:root {
--pulse-duration: 1.2s;
--pulse-min-scale: 0.9;
}
@keyframes callPulseVar {
0% {
transform: scale(var(--pulse-min-scale));
opacity: 0.7;
}
50% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(var(--pulse-min-scale));
opacity: 0.7;
}
}
.call-avatar {
animation: callPulseVar var(--pulse-duration) ease-in-out infinite;
}
这种方式在多人协作时尤其有用,能避免动画参数散落在各处。同时它不改变动画性能特征,仍只触及transform与opacity。
四、兼容性与降级处理
现代浏览器对@keyframes和animation支持已非常完善,但在极旧环境或某些嵌入式WebView中,可能不支持无限动画。此时应提供静态兜底样式,确保来电信息仍清晰可读。
我们可以用@supports做特性检测,或在默认样式里直接写好最终可见状态,让动画仅作为增强。这样即使动画失效,用户也不会漏接来电。
4.1 简单的降级写法
.call-avatar {
width: 120px;
height: 120px;
border-radius: 50%;
opacity: 1;
}
@supports (animation: callPulse 1s infinite) {
.call-avatar {
animation: callPulse 1.2s ease-in-out infinite;
}
}
如上,基础样式保证头像始终可见,支持动画的客户端才会附加脉冲效果。这种渐进增强思路能让来电界面更稳健。
五、完整示例整合
最后给出一个精简但完整的来电动画页面片段,包含滑入横幅、脉冲头像与摇晃铃铛,可直接放入项目观察效果:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<style>
@keyframes slideDown {
from { transform: translateY(-100%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes callPulse {
0% { transform: scale(0.9); opacity: 0.7; }
50% { transform: scale(1); opacity: 1; }
100% { transform: scale(0.9); opacity: 0.7; }
}
@keyframes ringShake {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(15deg); }
75% { transform: rotate(-15deg); }
}
.call-banner {
position: fixed; top: 0; left: 0; right: 0; height: 80px;
background: #2c3e50; color: #fff;
display: flex; align-items: center; padding: 0 20px;
animation: slideDown 0.4s ease-out forwards;
}
.call-bell { font-size: 32px; animation: ringShake 0.6s ease-in-out infinite; }
.call-avatar {
width: 120px; height: 120px; border-radius: 50%;
margin: 100px auto; background: #3498db;
animation: callPulse 1.2s ease-in-out infinite;
}
</style>
</head>
<body>
<div class="call-banner">
<span class="call-bell">🔔</span>
<span>来电:张三</span>
</div>
<div class="call-avatar"></div>
</body>
</html>
通过上述组合,你可以用纯CSS快速搭建出自然且不卡顿的来电动画。后续若接真实呼叫事件,只需用类名的增删控制动画容器的显示隐藏即可,不必改动核心样式。
CSS_animationkeyframes来电界面修改时间:2026-08-08 13:39:37