骨架屏样式必须内联到HTML的<head>中,否则SSR首屏会闪白或布局抖动;外链CSS或@import因加载延迟导致空白,而非占位;内联样式需精简、兼容、加!important,伪元素::before覆盖内容并配对定位显隐。

骨架屏必须内联到 HTML 的 <head> 中,否则 SSR/首屏直出时会闪白或布局抖动;外链 CSS 加载延迟会让用户看到空白,不是“占位”,而是“失位”。
为什么骨架屏样式不能用外链或 @import
服务端渲染(SSR)吐出的 HTML 是立即可解析的,但浏览器要等外部 CSS 文件下载、解析、注入后才应用样式。这中间可能有 100–300ms 空白——尤其在弱网下,用户看到的就是白屏或内容突然弹出。
-
@import会阻塞并串行加载,比<link>更慢,完全不适合首屏关键样式 - Next.js / Nuxt 等框架的
<Head>或useHead默认不内联,需显式配置script: { strategy: 'beforeRender' }类似机制 - 构建时可用
html-webpack-plugin的inject: 'head'+templateParameters注入内联<style>
怎么写最小可行的内联骨架样式
内联样式必须精简、确定、兼容。不能用 CSS 变量、嵌套、rem 单位(iOS Safari 不支持 rem 在 background-size 中),所有关键规则加 !important 防覆盖。
- 只保留结构类:
.skeleton、.skeleton-avatar、.skeleton-title等,每个都设固定宽高或aspect-ratio - 动画用简短唯一名(如
sh),避免与后续 CSS 冲突 - 头像用
radial-gradient+border-radius: 50%+overflow: hidden,别用background-image引图片 - 段落行用
background-repeat: repeat-y+ 小高度渐变,模拟多行文字留白
<style>
@keyframes sh { from { background-position: -200px 0; } to { background-position: 200px 0; } }
.skeleton { background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 300px 100%; animation: sh 1.5s infinite; }
.skeleton-avatar { width: 40px; height: 40px; border-radius: 50%; overflow: hidden; }
.skeleton-title { width: 60%; height: 20px; margin-top: 12px; border-radius: 4px; }
</style>
伪元素实现骨架层的关键细节
用 ::before 覆盖真实内容是最稳妥的方案,它不增加 DOM 节点,也不影响框架的 diff 逻辑,但必须配对控制定位和显隐。
立即学习“前端免费学习笔记(深入)”;
- 容器必须设
position: relative,伪元素设position: absolute; top: 0; left: 0; right: 0; bottom: 0; - 伪元素
z-index要高于真实内容,且background必须带渐变+background-size: 200% 100% - 隐藏时用
display: none,**不是等动画结束再删**,否则会有“闪一下”感;JS 加载完成瞬间就移除类或设display: none - 移动端务必加
overflow: hidden,否则圆角区域扫光动画会漏白边
最易被忽略的是:骨架容器的盒模型(padding、margin、line-height)必须和真实内容一致,否则加载完成那一刻会 layout shift —— 用户感知到的不是“加载完成”,而是“页面跳了一下”。


















