html原生loading属性仅控制加载时机,不提供占位逻辑,需手动实现骨架屏并配合js监听图片加载完成状态来切换显隐。

HTML原生loading属性不支持自定义占位符
浏览器原生的 loading="lazy" 只控制加载时机,不提供任何占位逻辑——它不会自动显示骨架屏、灰色方块或 loading 动画。所谓“懒加载占位符”,其实是你手动实现的视觉层 + 原生加载机制的组合。
常见错误现象:<img src="a.jpg" loading="lazy" alt=""> 在图片未加载时显示空白或塌陷布局,用户感知卡顿甚至误以为失败。
- 必须自己写占位结构(比如
<div class="skeleton"></div>),再配合 CSS 控制显隐 - 不能依赖
loading属性触发占位逻辑,它只影响 fetch 行为,不发事件、不改 DOM 状态 - 若用
IntersectionObserver手动控制加载,才可能同步更新占位状态;但此时已绕过原生loading
CSS骨架屏占位要避免布局偏移(layout shift)
骨架屏本质是用纯色块模拟图像尺寸,一旦尺寸不准,图片加载后会把下方内容往下推,触发布局抖动(CLS 指标恶化)。这不是样式“不好看”的问题,而是核心性能指标受损。
- 占位容器必须有明确宽高(推荐用
aspect-ratio或 padding-bottom 百分比方案) - 禁用
width: 100%; height: auto这类依赖内容撑开的写法 - 如果图宽高不确定,宁可用固定比例(如
aspect-ratio: 4/3)也不留空高 - 骨架元素建议用
background-color+border-radius模拟,别用 SVG 占位(体积大、渲染慢)
示例:一个安全的响应式占位容器
立即学习“前端免费学习笔记(深入)”;
<div class="img-placeholder" style="aspect-ratio: 16/9; background: #f0f0f0;">
@@##@@
</div>
.img-placeholder img {
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transition: opacity 0.2s;
}
.img-placeholder img.loaded { opacity: 1; }
监听图片加载完成并切换占位状态得靠onload或decode()
仅靠 CSS 和 HTML 无法知道图片何时真正可渲染。想让骨架屏在图就绪时淡出,必须介入 JS 生命周期。但要注意:直接绑 onload 在 <img src="real.jpg" loading="lazy" alt="..."> 上,对缓存命中或 error 状态覆盖不全。
- 优先用
img.decode()(返回 Promise),它确保图像解码完成,比onload更可靠 - 必须同时监听
onerror,否则加载失败时骨架屏永远不消失 - 不要在
IntersectionObserver回调里直接设置src后就认为“已加载”——那只是开始请求,不是完成 - 服务端渲染(SSR)场景下,需在客户端补监听,否则首屏骨架不消失
简短实操示意:
const img = document.querySelector('img');
img.addEventListener('load', () => img.classList.add('loaded'));
img.addEventListener('error', () => img.classList.add('failed'));
// 或更稳一点:
img.decode().then(() => img.classList.add('loaded')).catch(() => img.classList.add('failed'));
第三方库如lazysizes默认也不带骨架屏
像 lazysizes、lozad.js 这些懒加载库,专注解决资源延迟加载和 IntersectionObserver 封装,它们不处理视觉占位。所谓“集成骨架屏”,全是项目里自己叠加的 CSS + JS 逻辑。
- 引入
lazysizes后仍需手动加data-src、占位 div、状态 class 和切换逻辑 - 有些插件(如
lazysizes/plugins/unveilhooks/ls.unveilhooks.min.js)能帮你触发自定义钩子,但骨架显隐仍是你要写的 - 若用 React/Vue,组件库里的
Suspense或v-lazy同样不内置骨架——那是 UI 框架层该做的事
最容易被忽略的一点:占位逻辑和懒加载逻辑要共用同一套“是否进入视口”的判断依据,否则会出现“图还没进视口,骨架先消失了”这种错乱。











