用linear-gradient+background-position实现骨架屏流光效果,需设background-size≥200% 100%、渐变方向为90deg/to right、元素有明确宽高、动画timing-function为linear、时长1.5s–2s,并避免opacity切换以防止布局偏移。

怎么用 linear-gradient + background-position 做流动光效
骨架屏的“动起来”感不靠 GIF 或 JS 动画,核心是用渐变背景横向平移。关键不是颜色多复杂,而是 background-size 和 background-position 的配合必须让高亮条能“扫过”整个区域。
常见错误:写成 background: linear-gradient(90deg, #f0f0f0, #e0e0e0) 就完事——这只会生成一条静止色带,毫无扫描感。
-
background-size至少设为200% 100%,否则background-position移动时会露底色 -
@keyframes中必须从正向大值移到负向(如200% → -200%),不能只写0% → 100%,否则动画会卡在边界 - 推荐用
linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent),比纯灰阶更轻、更接近“光扫过”的物理直觉
为什么 aspect-ratio 比 padding-top 百分比更值得优先用
现代浏览器(Chrome 88+、Firefox 89+、Safari 15.4+)已原生支持 aspect-ratio,它直接声明宽高比,无需父容器 hack,也不依赖内容流或伪元素撑高。
用 padding-top 百分比的老方案,在 Flex/Grid 容器里容易失效;而 aspect-ratio 是 CSS 层级的布局约束,和 display 类型无关。
- 图片类骨架:直接写
aspect-ratio: 4/3或16/9,再配width: 100% - 兼容性兜底可加
height: 0; padding-top: 75%(对应 4/3),但仅当必须支持 Safari 15.3 及更早版本时才启用 - 切忌混用:同时写
height和aspect-ratio会导致冲突,浏览器可能忽略后者
如何避免骨架屏 DOM 干扰真实内容或屏幕阅读器
骨架屏不是遮罩层,也不是透明化真实节点——它是独立、语义空、无障碍友好的占位结构。一旦复用真实 <div class="title"> 加背景,就等于把加载逻辑耦合进语义结构里。
<p>最常被忽略的点:骨架元素如果含文字、<code>alt、aria-label,会被屏幕阅读器读出,造成信息污染。
- 所有骨架
<div> 必须无文本内容、无 <code>alt、无aria-*(除非显式设aria-hidden="true") - 禁用
content伪元素(如::before { content: "" }不要写成content: "loading...") - 切换真实内容时,用
replaceWith()或框架的v-if/useState替换整段 DOM,而不是仅改opacity或visibility - Vue 中优先用
v-if="isLoading",而非v-show - React 中用
{ isLoading ? <skeleton></skeleton> : <realcontent></realcontent> },确保骨架组件 unmount - 纯 HTML/CSS 场景下,JS 加载完成回调里调用
element.replaceWith(realElement),而非element.style.opacity = 0
为什么不用 opacity 动画切换骨架与真实内容
opacity 看似简单,但它触发的是全层重绘(repaint),尤其在滚动中叠加多个骨架卡片时,帧率会明显掉。更严重的是:它不释放布局空间,导致骨架元素仍参与文档流计算,SSR 水合后易出现 layout shift。
真正轻量的切换方式,是让骨架 DOM 在数据就绪后被完全卸载——既省内存,又杜绝样式残留风险。
骨架屏最难的从来不是“怎么动”,而是“动完怎么彻底消失”。DOM 不清理,动画不停止,aspect-ratio 不生效,就永远在和 layout shift 较劲。











