骨架屏必须用 relative + 伪元素,因其可实现占位不挤占、动画可复用、结构零侵入;直接插入 DOM 会破坏 SSR、SEO 和无障碍,而伪元素配合 relative 容器能锚定视觉位置且不触发重排。

骨架屏为什么必须用 relative + 伪元素?
因为骨架屏的核心诉求是「占位不挤占、动画可复用、结构零侵入」。如果直接在内容容器里插入 <div class="skeleton">,会破坏原有 DOM 结构,影响 SSR 渲染顺序、SEO 和无障碍访问;而用 ::before 或 ::after 伪元素配合 position: relative 容器,能让骨架始终锚定在目标区域的视觉位置,且不参与文档流——加载完成时只需 visibility: hidden 或 opacity: 0 切换,完全避免重排。
relative 容器的三个硬性要求
不是所有父容器都适合当骨架屏载体。以下三点漏掉任一,动画就会错位或失效:
-
position必须显式设为relative(不能依赖默认值或static) - 容器需有明确宽高(
height不能是auto,否则伪元素top/left基准丢失) - 若容器内含浮动/绝对定位子元素,需确保其不影响容器高度计算(常用
overflow: hidden或display: flow-root)
伪元素动画的关键参数组合
只用 animation: loading 1.4s ease-in-out infinite 不够——容易卡顿、闪烁或横向偏移。真正稳定的写法要同时控制三处:
-
background-image用linear-gradient模拟高亮扫光,方向必须设为to right(否则在 RTL 页面翻转) -
background-size设为200% 100%,配合background-position从-100% 0动画到100% 0,才能保证扫光平滑贯穿整个区域 - 动画延迟用
animation-delay: -0.5s而非0s,让多块骨架屏出现错峰效果,更接近真实加载节奏
`.card {
position: relative;
height: 120px;
overflow: hidden;
}
.card::before {
content: "";
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading 1.4s ease-in-out infinite;
animation-delay: -0.5s;
}
@keyframes loading {
0% { background-position: -100% 0; }
100% { background-position: 100% 0; }
}`
加载完成时隐藏骨架屏的可靠方式
别用 display: none——它会触发重排,导致内容“跳一下”;也别只靠 opacity: 0——透明但仍在点击流中。最稳妥的是组合操作:
立即学习“前端免费学习笔记(深入)”;
- 先加类名如
is-loaded,在 CSS 中写.card.is-loaded::before { opacity: 0; transition: opacity 0.3s } - JS 中等内容渲染完成后,再通过
setTimeout(() => el.classList.add('is-loaded'), 0)触发过渡(避免同步阻塞) - 若骨架需支持服务端预渲染,务必在 HTML 中初始不带
is-loaded,由客户端 JS 控制,否则 SSR 会提前隐藏
骨架屏的麻烦不在实现,而在它必须和真实内容的盒模型、字体加载、图片解码节奏严丝合缝——差一个像素的 line-height 或一行未声明的 font-display,都会让扫光动画和文字出现错层。


















