约 6 分钟读完 · 更新于 2026-10-21 · 文中每条都能在下面的配套工具里动手验证
实测中骨架屏不会让接口更快;它的价值是让用户提前看到布局结构,降低「页面坏了」的焦虑,并把加载后的布局跳动(CLS)压到接近 0。所以判断要不要做骨架,先看这块区域加载后会不会移动物体:会移动(卡片流、详情页头部)就值得做;不变(一行文字按钮)转圈就够了。
| 原始元素 | 骨架形态 | 要点 |
|---|---|---|
| 标题 / 段落文本 | 圆角灰条,宽度按字数估 | 多行时最后一行做短,模拟自然段落 |
| 图片 / 视频 | 等宽高比的灰块 | 锁定 aspect-ratio,加载后不跳 |
| 按钮 / 链接 | 圆角块 | 保留原 padding,尺寸才对得上 |
| 整个卡片 | 灰块组合 | 结构对齐原卡片,间距一致 |
| 图标 | 小方块或省略 | 太小的元素做骨架反而显乱 |
shimmer(扫光)适合大面积卡片,方向感强、暗示「正在加载」;pulse(呼吸)适合小面积、列表行。同一页面只用一档,混用会显得乱。用户开了「减少动态效果」时必须降级为静态灰块——这不是可选项,是规范要求。
.sk { position: relative; overflow: hidden; background: #e5e7eb; border-radius: 6px; }
.sk::after { content: ""; position: absolute; inset: 0;
background: linear-gradient(90deg, transparent, rgba(255,255,255,.65), transparent);
transform: translateX(-100%); animation: sk-sweep 1.4s infinite; }
@keyframes sk-sweep { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .sk::after { animation: none; content: none; } }骨架化用户 HTML 时务必: 1. 剥掉 <script> 与 on* 事件属性,避免注入 2. 文本节点按长度估宽,图片按 aspect-ratio 占位 3. 节点数设上限(如 800),防止巨型文档卡死主线程
服务端渲染时输出的骨架只是初始 HTML,真实内容随后注入,搜索引擎渲染时会执行 JS 看到最终内容。真正要避免的是「永远只有骨架」——内容必须能在无交互的情况下到达 DOM。
确认动画只动 transform 和 opacity(合成层属性),别动 background-position 或 width;扫光层用 ::after 加 will-change: transform 即可稳定 60fps。
把灰条灰块做成无逻辑的展示组件(Skeleton/SkeletonText),业务组件里 loading ?