骨架渲染塌陷主因是未设尺寸,须显式定义宽高;流光动画应基于background-position实现;DOM替换需结构对齐且禁用innerHTML;IntersectionObserver需合理配置rootMargin;骨架必须早于JS加载。

骨架元素一渲染就塌掉,90% 是没设尺寸
空 <div> 默认是 0×0,只靠 <code>background-color 帮不上忙。浏览器不会为你“猜”高度,文字行、图片区域、按钮都会挤成一团,后续真实内容插入必然重排闪动。
必须显式设置尺寸:
- 文字行:用
line-height × 行数算高,比如三行摘要就写height: 48px(假设line-height: 16px),禁用height: 100%—— 父容器没高时它直接失效 - 图片占位:优先用
aspect-ratio: 16 / 9;不支持的旧浏览器 fallback 到padding-top: 56.25%+position: relative+ 子元素position: absolute - 按钮/卡片等块级占位:固定宽高或
min-width/min-height,别依赖width: 100%—— 容器宽度可能还没确定 - 所有骨架元素加
overflow: hidden,否则渐变动画会从圆角边缘溢出
流光动画别用 opacity 或 transform,用 background-position
opacity 淡入淡出或 transform: translateX() 移动伪元素,在中低端设备上容易掉帧;真正稳定的是纯背景位移动画,GPU 合成友好、不触发重绘。
核心写法只有三行 CSS:
立即学习“前端免费学习笔记(深入)”;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: loading 2s linear infinite;
@keyframes loading { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } }
注意点:
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 禁用
ease-in-out—— 光效会在两端停顿,显得卡顿;必须用linear - 动画时长控制在 1.5–2.5s:快于 1.5s 显得急促,慢于 2.5s 用户已开始怀疑卡住
- 低配设备兜底:
@media (prefers-reduced-motion: reduce) { animation: none; }
DOM 替换必须结构对齐,不能靠 innerHTML 清空再塞新 HTML
用 element.innerHTML = '' 清掉骨架再插入真实 HTML,会导致 Vue/React 组件状态丢失、第三方插件(如代码高亮、图表)没重初始化、focus 断掉、SSR hydration 错位。
安全替换方式只有两种:
- 用
<template></template>预存真实结构,加载完成后调用skeletonEl.replaceWith(realContent)—— DOM 节点完全替换,结构、class、data 属性全对齐 - 骨架和真实内容使用**完全一致的 class 名、嵌套层级、属性名(如
data-id)、甚至注释位置**;哪怕多一个空格,hydration 都可能失败 - 绝对禁用
v-show或visibility: hidden控制显隐 —— 它们仍参与布局计算,SSR 场景下 hydration 会错位
无限滚动中骨架接续卡顿,根因是 IntersectionObserver 配置不当
监听 window.onscroll 手动算滚动位置,高频触发、易误判、性能差;而用 IntersectionObserver 监听页尾占位符,才是稳定方案。
关键配置项:
-
rootMargin: '200px'—— 提前 200px 触发加载,留出网络与渲染缓冲,避免用户看到空白 - 一次加载中,
unobserve()当前占位符;加载成功且有更多数据时,再observe()新占位符 —— 防止重复请求 - 服务端必须返回
hasMore: true/false,前端据此决定是否继续挂载 observer - 骨架项和真实列表项 DOM 结构必须严格对齐:同级数量、class、属性、顺序,差一点就会导致 focus 断掉或插件未重初始化
最常被忽略的点:骨架不是“加个动画就行”,而是要从 HTML 解析阶段就存在 —— 它得比 JS 更早出现。Vue 中 loading: true 必须在 setup() 顶层声明,React 中 useState(true) 初始化后立即发起请求并保持 loading 状态,否则用户第一眼看到的仍是白屏。


















