骨架屏与懒加载必须协同工作:骨架屏先直出占位,懒加载后调度资源,二者结构需完全一致,且骨架须纯css实现、原子化替换、适配深色模式与动效降级。

图片懒加载和骨架屏不是“并列选项”,而是必须协同工作的两个环节——骨架屏负责结构占位,懒加载负责资源调度,二者配合才能避免“骨架刚稳住,图片一涌而出导致布局跳动”的问题。
骨架屏必须先于懒加载触发,且结构完全匹配
骨架屏的图片占位容器(如 .skeleton-image)要和真实 <img> 标签在 DOM 层级、class 名、宽高约束、盒模型上完全一致。比如真实图用了 aspect-ratio: 4/3; object-fit: cover;,骨架容器就得写死相同 aspect-ratio,不能靠 padding-top 估算;真实图父容器设了 overflow: hidden,骨架也得加,否则流光动画会溢出圆角边界。
- 禁止用
<img src="placeholder.png">做骨架图——它会发起 HTTP 请求,干扰 LCP 统计,还可能阻塞解析 - 骨架图区域必须是纯 CSS 占位:固定尺寸 +
background: linear-gradient()+background-size: 200% 100% - 真实
<img>的loading="lazy"属性只控制资源加载时机,不改变 DOM 结构;骨架屏必须在服务端直出 HTML 中就存在,不能等 JS 注入
懒加载时机要让骨架“撑得住场子”
懒加载默认在图片进入视口时才开始请求,但若此时骨架已移除、真实图片又未完成解码渲染,用户会看到空白或回流抖动。关键在于延长骨架生命周期,直到图片真正可渲染。
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
- 给
<img>添加decoding="async",避免解码阻塞主线程 - 监听
img.onload和img.onerror,而不是仅靠 IntersectionObserver 判断“是否进入视口”就移除骨架 - 对首屏关键图(如 banner、头图),禁用
loading="lazy",改用loading="eager",确保骨架切换后能立刻渲染
切换过程必须原子化,避免二次重排
骨架屏不是“隐藏”,而是“替换”:真实图片加载完成并渲染稳定后,再调用 skeletonEl.remove() 彻底销毁节点。若只用 display: none 或 opacity: 0,骨架的 CSS 动画仍在后台运行,长期驻留会拖慢页签性能。
- 推荐用
replaceChildren()直接将骨架节点替换成完整<img>元素,保证 DOM 更新原子性 - 若用 Vue/React,骨架组件与图片组件应共用同一份数据判断逻辑,例如
v-if="!imageSrc"而非v-if="loading",避免状态不同步 - 所有骨架容器加上
contain: layout paint style,让浏览器跳过不可见区域的布局计算(注意 Safari 15.4 前需@supports包裹)
深色模式与动效降级要同步适配
骨架的背景色、流光动画、甚至图片 fallback 都需随系统主题变化,否则深色模式下灰块会刺眼;同时要考虑低性能设备的动画体验。
- 用 CSS 变量定义骨架色:
--skeleton-bg: var(--color-surface, #f0f0f0),绑定到:root或组件 scope - 流光动画优先用
background-position位移,Safari 或低端 WebView 不支持时降级为transform: translateX()+opacity - 对启用了
prefers-reduced-motion的用户,直接关闭所有骨架动画:@media (prefers-reduced-motion: reduce) { .skeleton-image { animation: none; } }
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










