FOUC导致图片闪一下再淡入,需内联关键样式(opacity: 0 + @keyframes)、用IntersectionObserver触发、动画须定义from/to并设animation-fill-mode: forwards,背景图渐变需绕道opacity或background-position实现。

图片还没加载完就闪一下再淡入?这是 FOUC,得用内联关键样式压住
浏览器渲染 HTML 时若 CSS 还没加载完,img 会先以默认不透明状态渲染,等样式生效后再变 opacity: 0,造成“闪一下”。这不是动画问题,是渲染时序问题。
必须把 opacity: 0 和 @keyframes 定义直接写在 <head> 的 <style> 里,不能放外部 CSS 文件。否则无法保证样式早于图片渲染生效。
- 不要用
style="opacity: 0"写在img标签上——内联样式优先级高,但 JS 后续操作 class 时容易冲突 - 更稳妥的做法:初始用
visibility: hidden或display: none隐藏图片,等 JS 确认可动画再切到opacity: 0并加动画 class - 如果页面有 SSR 或静态生成,确保服务端已注入该内联样式块
用 IntersectionObserver 替代 onload 触发动画更可靠
img.onload 只表示资源加载完成,不保证样式就绪,也不处理缓存图片瞬间渲染的问题——缓存图片可能在 onload 前就已显示,opacity: 0 来不及应用。
IntersectionObserver 监听图片进入视口的时机,既避开加载时序干扰,又能按需触发,更适合现代渐现场景。
立即学习“前端免费学习笔记(深入)”;
- 初始化时给图片加
class="fade-in-trigger",CSS 中设opacity: 0+ 动画 - JS 中监听
.fade-in-trigger元素,一进入视口就添加fade-in-active类触发动画 - 记得调用
observer.unobserve(el)避免重复触发 - 对首屏图片,可配合
loading="lazy"属性减少初始请求压力
@keyframes 必须写全 from 和 to,且要配 animation-fill-mode: forwards
只写 to { opacity: 1 } 是无效的——动画没有起点定义,浏览器不知道从哪开始过渡。
必须明确定义起始和终点,并用 forwards 保持最终状态,否则动画结束瞬间会回退到 opacity: 0。
- 正确写法:
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } - 对应 class 必须带
animation-fill-mode: forwards,或简写为animation: fadeIn 0.6s ease-out forwards - 避免混用
transform和opacity在同一动画中触发布局重排;如需位移,用transform: translateZ(0)启用硬件加速 - 动画时长建议 0.4–0.8 秒,太短感知不到,太长影响节奏
背景图切换想加渐变?别碰 background-image 的 transition
background-image 是非数值属性,原生不支持 transition,直接写 transition: background-image 0.5s 会被浏览器忽略。
真正能动的是 opacity 和 background-position——得用它们模拟切换效果。
- 双层方案:用
::before承载第二张背景图,初始opacity: 0,hover 或 JS 切换时过渡到opacity: 1 - 单图位移方案:设
background-size: 200% 200%,用transition: background-position控制滚动,适合纹理/渐变微调 - 绝对不要在父容器上同时设
overflow: hidden和transform,可能触发渲染异常导致渐变撕裂


















