红绿灯动画需用@keyframes手动分配百分比实现非匀速切换,配合负animation-delay对齐初始状态,禁用opacity避免语义错误,采用高对比度无障碍色值并用css变量适配响应式。

用 @keyframes 控制三色帧序和停顿时间
红绿灯不是匀速切换,而是「红→黄→绿→黄→红」循环,每段停留时长不同(常见为红 5s、黄 1s、绿 4s、黄 1s)。直接用 animation-timing-function: steps() 无法精确控制各色持续时间,必须手动拆解关键帧百分比。
核心是把整个周期(比如 11s)映射到 0%–100%,按比例分配每段:红占 0%–45.45%(5/11),黄 45.45%–54.55%(1/11),绿 54.55%–90.9%(4/11),再一个黄 90.9%–100%。这样能避免因浏览器插值导致的中间色过渡。
示例片段:
@keyframes traffic-light {
0%, 45.45% { background: red; }
45.45%, 54.55% { background: yellow; }
54.55%, 90.9% { background: green; }
90.9%, 100% { background: yellow; }
}
用 animation-delay 对齐初始状态
页面加载后第一帧未必从红灯开始——如果动画已运行过半,可能直接跳到黄或绿。要确保首次渲染即显示红灯,得让动画“假装”已运行了对应延迟时间。
比如总周期 11s,红灯在开头占 5s,那初始状态为红时,animation-delay 应设为 -5s,相当于把动画倒带 5 秒,停在红灯起点。
实际写法需配合 animation-iteration-count: infinite:
- 想从红灯开始 →
animation-delay: -5s - 想从绿灯开始 →
animation-delay: -(5+1)s = -6s - 延迟值必须为负,且绝对值 ≤ 总周期,否则行为不可控
避免用 opacity 或 filter 模拟闪烁
有人试图用透明度淡入淡出来“模拟”灯亮灭,这会破坏红绿灯的语义逻辑:真实红绿灯是「全亮 / 全灭」,不是渐变。用 opacity 还会触发重绘(paint),影响性能;更严重的是,屏幕阅读器可能误读为内容不可用。
正确做法是只切换 background-color 或 box-shadow(如加发光效果),并确保颜色符合无障碍对比度(WCAG AA 要求至少 4.5:1):
- 红:推荐
#d32f2f(非纯红 #ff0000,后者在白底上对比度不足) - 绿:用
#388e3c(比 #00ff00 更稳) - 黄:选
#fbc02d(避免荧光黄 #ffff00 在 OLED 屏上过曝)
响应式下慎用固定 animation-duration
在小屏设备上,用户可能离屏幕更近,11s 周期显得过长;而大屏展厅场景可能需要更快节奏。硬编码 animation-duration: 11s 缺乏适应性。
更稳妥的方式是用 CSS 自定义属性 + JS 动态调整:
:root {
--light-cycle: 11s;
}
.traffic-light {
animation: traffic-light var(--light-cycle) infinite;
}
然后在 JS 中根据屏幕宽度或用户偏好修改 --light-cycle 值。注意:直接改 style.animationDuration 会重置动画,应优先走 CSS 变量路径。
真正难的不是写出动画,而是让红、黄、绿三色在任意设备上都清晰可辨,且不干扰色觉障碍用户——这点常被忽略。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











