骨架屏需结构对齐与时机控制:用aspect-ratio或padding-top实现响应式占位,统一box-sizing、line-height、display及字体度量,禁用visibility:hidden,优先采用svg骨架确保缩放稳定,vue/react中依据data空值而非loading状态精准显隐。

骨架屏不是靠 CSS 动画“假装”加载,而是用结构化的占位元素匹配真实 DOM 布局,在数据未就绪时提前渲染视觉框架——关键在“结构对齐”和“时机控制”,否则会闪动或错位。
怎么用 HTML + CSS 写出不跳动的骨架占位块
骨架屏失效的主因是占位元素尺寸/位置和真实内容不一致。必须让 <div class="skeleton-item"> 和后续 <code><img>、<p></p> 使用完全相同的盒模型(box-sizing: border-box)、外边距策略(避免用 margin-bottom 而改用 gap 或 padding)和字体度量(骨架文本用 line-height + font-size 模拟,而非空格占位)。
常见错误:直接给 .skeleton-item 设固定 height,但真实图片可能宽高比不同;正确做法是用 aspect-ratio 或 padding-top 百分比实现响应式比例占位:
.skeleton-image {
aspect-ratio: 16 / 9;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading 1.5s infinite;
}
- 所有骨架元素需设
display: block或与真实内容一致的display值(如列表项用display: flex) - 文字行高必须和真实文本一致:
line-height: 1.5对应真实段落的line-height,否则换行位置偏移 - 禁用
visibility: hidden切换骨架——它保留布局空间但不可交互;改用opacity: 0+pointer-events: none配合过渡
Vue/React 中如何精准控制骨架屏显隐时机
骨架屏不是等 fetch 开始才显示,而应在组件挂载、路由就绪、且数据为空时立即激活。在 Vue 中,不要监听 loading 状态变量,而应检查 data === null || data.length === 0;React 同理,用 useEffect 对比 data 是否从 undefined 变为有效值。
容易踩的坑:
- SSR 场景下,服务端已渲染真实内容,客户端 hydration 时骨架屏又闪一下——需在
mounted或useLayoutEffect中判断document.readyState === 'complete'再决定是否显示骨架 - 使用
keep-alive的 Vue 页面,缓存后data仍存在,但用户刷新页面时应重新触发骨架——需监听activated钩子并重置加载态 - React 中若用
useState存储数据,初始值设为null而非[],否则骨架逻辑无法触发
为什么用 SVG 骨架比纯 CSS 更稳
CSS 骨架依赖 background-image 或伪元素,但遇到 transform: scale()、will-change: transform 或父容器 overflow: hidden 时易被裁剪或失真;SVG 骨架通过 <rect></rect> 和 <circle></circle> 原生矢量绘制,不受缩放影响,且可精确控制圆角、描边、渐变方向。
示例:头像骨架用 SVG 替代 border-radius 圆角 div:
<svg width="40" height="40" viewbox="0 0 40 40"><circle cx="20" cy="20" r="20" fill="#f0f0f0"></circle></svg>
- SVG 占位块可直接内联,无额外请求,且支持
currentColor适配主题色 - 动画用
<animate></animate>元素比 CSS@keyframes更轻量,尤其在列表项多时 - 但注意:IE11 不支持
<animate></animate>,需降级为 CSS 动画或 JS 控制stroke-dasharray
真正难的不是画几个灰色方块,而是让骨架的盒模型、层叠上下文、字体度量、响应行为和真实内容严丝合缝——任何一处偏差都会导致加载瞬间的 layout shift,用户感知就是“抖了一下”。上线前务必在弱网(Throttling: Fast 3G)下录屏检查首帧到数据渲染的整个流程。











