纯CSS移动端骨架屏需用两层linear-gradient叠加实现结构与扫光动效,background-size禁用rem/vw而用px,动画仅靠background-position触发GPU加速,各区块用不同渐变组合绘制,opacity切换显隐防动画中断。

纯 CSS 实现移动端首屏骨架屏,linear-gradient 是最轻量、兼容性最好、性能最优的方案——它不发请求、不占 JS 执行资源、动画由 GPU 加速,iOS Safari 12.2+ 和 Android Chrome 62+ 均可稳定运行。
为什么必须用两层 linear-gradient 叠加?
单层渐变只能铺满一种色块,无法同时表达「背景灰度 + 扫光动效」两个视觉层。真实骨架屏需要:底层是静态结构(如头像圆角、标题长条),上层是一条横向移动的半透光条模拟“扫描感”。
- 错误写法:
background: linear-gradient(90deg, #f0f0f0, #e0e0e0)—— 光条不会动,且无法控制尺寸 - 正确结构:
background-image必须显式声明两层,顺序为「底层结构渐变,顶层扫光渐变」 - 关键约束:两层必须共用同一组
background-size和background-position,否则动画错位
background-size 为什么不能用 rem 或 vw?
iOS Safari(包括所有 WebKit 内核)不支持 rem、vh、vw 作为 background-size 的单位,只认固定像素或百分比。直接写 background-size: 20rem 100% 在 iPhone 上会退化为默认值,导致光条拉伸变形、动画卡顿甚至消失。
- 安全写法:
background-size: 200px 100%(宽度设为大于容器的固定值,确保动画有足够位移空间) - 适配逻辑交给容器本身:用
width: 100%; max-width: 100%;配合viewport中的width=device-width, initial-scale=1保证容器缩放正常 - 若需响应式光条宽度,可用 JS 动态写内联样式:
el.style.backgroundSize = `${window.innerWidth * 1.5}px 100%`
动画必须用 background-position,而不是 transform
transform: translateX() 看似更直观,但在部分安卓 WebView(尤其是旧版 UC、QQ 浏览器)中会完全失效;且触发重排,动画帧率不稳定。而 background-position 是纯合成层动画,GPU 可直接加速。
立即学习“前端免费学习笔记(深入)”;
- 正确动画定义:
@keyframes shine { from { background-position: -200px 0; } to { background-position: 200px 0; } } - 绑定时注意:必须搭配
background-repeat: no-repeat,否则重复会导致光条闪烁跳变 - 起始偏移设为负值(如
-200px):让光条从左外侧进入,避免首帧突兀出现在中间 - 不要在
:root或全局 class 上启用此动画,仅作用于具体骨架容器,例如.skeleton-card
如何用渐变“画”出头像、标题、段落这些不同形状?
不是靠一个大渐变填满整个容器,而是用多个 linear-gradient 或 radial-gradient 按需叠加,每个对应一个语义区块。
- 头像圆角:
background-image: radial-gradient(circle, #f0f0f0 0%, #f0f0f0 50%, transparent 50%)+background-size: 40px 40px - 标题长条:
linear-gradient(to right, #f0f0f0 0%, #e0e0e0 50%, #f0f0f0 100%)+background-size: 200px 16px - 段落短横线(多行):
linear-gradient(to right, #f0f0f0 0%, #e0e0e0 50%, #f0f0f0 100%)+background-size: 100% 12px+background-repeat: repeat-y - 留白控制靠透明间隙:比如段落之间用
margin-bottom: 8px,而非在渐变里硬塞空白色
最容易被忽略的是:动画容器的 opacity 切换必须用 opacity + transition,绝不能用 display: none —— 后者会中断正在运行的 background-position 动画,导致切换后光效“卡死”或重头开始。实际项目中,建议把骨架容器和真实内容用同一父容器包裹,仅靠 opacity 控制显隐,并设置 pointer-events: none 防止骨架层拦截点击。


















