最轻量兼容方案是纯CSS@keyframes配合animation-delay错开三点闪烁,IE10+支持;SVG适合高定制动画;JS适用于异步控制;需注意暗色模式对比度、移动端性能及点击区域保护。

用 CSS @keyframes 实现三点依次闪烁动画
最轻量、兼容性好(IE10+)、无需 JS 的方案就是纯 CSS 动画。核心是控制三个 • 或 <span> 元素的 opacity,用 @keyframes 错开它们的显示时机。
常见错误是直接给三个元素加相同动画,结果同步闪烁——必须用 animation-delay 手动错开 0.2s 间隔:
@keyframes dot-pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
.dot {
display: inline-block;
width: 8px;
height: 8px;
background: #333;
border-radius: 50%;
animation: dot-pulse 1.2s infinite;
}
.dot:nth-child(1) { animation-delay: 0s; }
.dot:nth-child(2) { animation-delay: 0.2s; }
.dot:nth-child(3) { animation-delay: 0.4s; }
- 动画时长建议设为 1.2s~1.4s,太短显得急促,太长加载感弱
- 不要用
visibility: hidden替代opacity,它会触发重排,影响性能 - 如果父容器有
text-align: center,记得给.dot加vertical-align: middle防止基线偏移
用 SVG + CSS 实现更精细的缩放+位移动画
当需要更高定制性(比如三点沿弧线运动、带阴影、响应式缩放),SVG 是更稳的选择。每个点用 <circle>,动画通过 transform 控制 scale 和 translateX。
容易踩的坑是 SVG 内联样式优先级高,外部 CSS 的 animation 可能不生效——务必把动画规则写在 <style> 标签里或外部 CSS 中,并确保选择器足够明确:
立即学习“前端免费学习笔记(深入)”;
<svg width="90" height="20" viewBox="0 0 90 20">
<circle class="dot-svg" cx="10" cy="10" r="3"/>
<circle class="dot-svg" cx="45" cy="10" r="3"/>
<circle class="dot-svg" cx="80" cy="10" r="3"/>
</svg>
<style>
.dot-svg {
fill: #007bff;
animation: svg-bounce 1.5s infinite;
}
.dot-svg:nth-child(1) { animation-delay: 0s; }
.dot-svg:nth-child(2) { animation-delay: 0.3s; }
.dot-svg:nth-child(3) { animation-delay: 0.6s; }
@keyframes svg-bounce {
0%, 100% { transform: scale(0.7) translateY(0); }
50% { transform: scale(1.2) translateY(-5px); }
}
</style>
- SVG 的
viewBox比固定宽高更适配响应式场景 - 避免在
<circle>上直接写style="animation:...",内联样式无法被:nth-child覆盖 - 移动端要注意
transform触发 GPU 加速,但过度缩放可能模糊,r值建议 ≥2.5
用 JavaScript 动态控制三点状态(适合异步加载场景)
当加载逻辑本身由 JS 控制(比如 fetch 请求中),用 JS 切换类名比纯 CSS 更可控。关键是避免手动操作 DOM 节点顺序,改用统一 class 控制状态。
典型错误是每次重新生成 HTML 字符串拼接三点——这会破坏事件绑定、触发重排,且无法复用已有节点:
<div id="loading-dots">
<span class="dot js-dot">•</span>
<span class="dot js-dot">•</span>
<span class="dot js-dot">•</span>
</div>
<script>
const dots = document.querySelectorAll('.js-dot');
let index = 0;
const cycle = () => {
dots.forEach((dot, i) => {
dot.classList.toggle('active', i === index);
});
index = (index + 1) % 3;
setTimeout(cycle, 400);
};
cycle();
</script>
- CSS 中只需定义
.dot.active { opacity: 1; },其余交由 JS 调度 - 不要用
setInterval,setTimeout递归更精准,避免定时器堆积 - 如果加载完成需销毁动画,记得保存
timeoutId并调用clearTimeout
移动端和暗色模式下的适配要点
三点动画在 iPhone Safari 或深色模式下容易看不清,不是“加粗”或“改颜色”就能解决的。
关键要区分语义:加载动画本质是“视觉节奏提示”,不是装饰。所以适配重点在对比度与节奏稳定性:
- 用
prefers-color-scheme: dark媒体查询单独设置暗色模式下的fill或background,别依赖系统自动反色 - 避免使用
#ccc这类灰度值,iOS 暗色模式下会变淡到不可见,改用#a0a0a0或带透明度的rgba(0,0,0,0.6) - 动画帧率在低端安卓机上易掉帧,可加
will-change: opacity提前提示渲染层,但仅对频繁变化的元素启用 - 如果三点用于按钮内部,确保点击区域不因动画缩小而误触——给父容器设
min-width或padding
真正难的不是让三点动起来,而是动得恰到好处:不抢眼、不干扰、不卡顿,且在各种屏幕和系统设置下都保持可感知的节奏。



















