骨架屏必须用无内容、无语义的空标签独立构建,结构需与真实DOM对齐;SSR时仅客户端注入;流光动画靠background-position位移实现;加载完成须remove()而非display:none;响应式用CSS媒体查询控制,尺寸需像素级对齐。

骨架屏必须用空标签独立构建,不能复用内容容器
直接在真实标题、段落元素上加 opacity: 0 或 visibility: hidden 是错的——这会让读屏器仍读出文字,且 JS 替换时容易漏掉节点或触发重排。骨架屏本质是“占位”,不是“遮罩”。
- 用
<div class="skeleton-title"></div>这类无内容、无语义的空标签,不带aria-label、不嵌<img>或<svg> - 结构层级要和真实 DOM 对齐(比如真实页有
.card > .card-header > h3,骨架就建.skeleton-card > .skeleton-header > .skeleton-line) - SSR 场景下,骨架只应在客户端注入;服务端返回的 HTML 里不该包含它,否则水合(hydration)会失败
流光动画靠 background-position 位移,别用 opacity 动画
单纯让元素闪烁或淡入淡出,缺乏“加载中”的质感。真正有效的骨架动画是模拟光线扫过,核心靠渐变背景横向位移。
- 关键 CSS 是
background-image: linear-gradient(90deg, transparent, #e0e0e0, transparent)+background-size: 200% 100%+animation: shine 2s infinite -
@keyframes shine中必须用background-position: -200% 0→200% 0,确保光效从左进、右出 - 避免用
filter: blur()模拟灰度——iOS Safari 16+ 仍有渲染抖动,改用background-color配合主题变量,如--skeleton-bg: #f0f0f0
加载完成必须彻底 remove(),不能只 display: none
很多项目只把骨架节点设为 display: none,但 @keyframes 动画仍在后台跑,单页应用反复进出同一页面时,内存泄漏和性能下降会明显。
- JS 加载完成后,务必调用
skeletonEl.remove(),而不是skeletonEl.style.display = 'none' - 如果骨架由 Web Component 渲染,要在
disconnectedCallback或unmounted钩子中清除所有定时器、事件监听和requestAnimationFrame句柄 - 动画时长建议控制在 1.5–2.5s:快于 1.5s 显得急促,慢于 2.5s 用户已开始怀疑卡顿
响应式骨架需用媒体查询控制 display,别靠 JS 切换结构
移动端常只需一行标题+头像,桌面端则显示完整卡片。用 JS 动态插入不同结构,既增加逻辑复杂度,又易引发水合不一致。
立即学习“前端免费学习笔记(深入)”;
- 统一写一套骨架结构,在 CSS 中用
@media (max-width: 768px)控制.skeleton-paragraph { display: none } - 避免在骨架内使用
width: 100%等依赖父容器的尺寸,改用固定值(如width: 200px)或min-width,防止 flex 布局下坍缩 - 深色模式下,骨架色值应随系统主题切换,推荐用
color-scheme: light dark+CSS custom property,而非硬编码十六进制



















