骨架屏是视觉占位与渐变过渡组合,用linear-gradient+background-position动画模拟扫描光效,需固定尺寸、脱离文档流、JS控制显隐,并适配SSR/CSR渲染时机。

用 animation + keyframes 模拟骨架屏闪烁效果
骨架屏本质不是“加载中动画”,而是视觉占位+渐变过渡的组合。CSS 动画只负责「模拟内容未就绪时的视觉节奏」,不参与数据加载逻辑。核心是用 linear-gradient 生成灰白条状背景,再通过 animation 移动 background-position 制造扫描光效。
- 推荐使用
to right方向的线性渐变,比径向更易控制扫描节奏 - 动画时长建议设为
1.5s ~ 2.5s,太短显急促,太长降低感知响应 - 必须加
background-size: 200% 100%,否则background-position位移无效
@keyframes loading-skeleton {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.skeleton {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading-skeleton 2s ease-in-out infinite;
}
骨架元素需脱离文档流避免重排
如果直接给 按钮、头像、卡片的骨架形态差异大,不能靠一个 class 全局覆盖。比如头像要圆角+渐变遮罩,列表项需等高行高+多段灰条,而按钮需要宽度自适应+内边距留白。 服务端渲染(SSR)或静态生成(SSG)页面首次加载时,骨架屏可能一闪而过甚至不出现,因为 HTML 已含真实内容,JS 还没执行完。此时需配合服务端逻辑,在数据未就绪时主动输出骨架 HTML 片段。 立即学习“前端免费学习笔记(深入)”;position: absolute 叠加,或用 visibility: hidden 控制显隐而非 display: none。
position: relative,内部骨架元素设 position: absolute; top: 0; left: 0; width: 100%; height: 100%
visibility: hidden,而不是移除 DOMheight: auto,必须固定高度或用 aspect-ratio 保形不同组件需定制化骨架结构
border-radius: 50% + background-image: radial-gradient(...)
,每行设不同 width 模拟长短文本::before 做骨架——它无法继承父容器的宽高约束,响应式下容易错位.avatar-skeleton {
border-radius: 50%;
background: radial-gradient(circle, #f5f5f5 20%, #e8e8e8 80%);
}
.skeleton-line {
display: block;
height: 16px;
margin: 8px 0;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading-skeleton 2s ease-in-out infinite;
}
SSR 或首屏直出时骨架屏容易失效
骨架屏最难的不是动画本身,而是如何让它在各种渲染模式下稳定介入 DOM 生命周期 —— CSS 负责动效,JS 负责时机,HTML 结构负责占位精度,三者缺一不可。loading.tsx 或 loading.vue 中,由框架自动接管useState(false) 控制骨架显隐,但首次渲染仍需同步判断 data === null










