为什么我的Vue页面CLS总是超标?图片加载导致布局偏移怎么解决?

UX-雪利 阅读 20

我在用Vue做商品列表页,发现Lighthouse测出来的CLS经常超过0.25,主要问题好像是图片加载时没占位,导致下面的内容突然被撑开。我明明给img加了固定宽高,但还是不行。

试过用v-lazy或者CSS aspect-ratio,但效果不稳定。是不是哪里写错了?

<template>
  <div class="product-list">
    <div v-for="item in products" :key="item.id" class="card">
      <img :src="item.image" width="300" height="300" />
      <h3>{{ item.name }}</h3>
    </div>
  </div>
</template>
我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
一景红
一景红 Lv1
当时我也卡在这,CLS问题确实让人头疼。你的思路是对的,但固定宽高还不够,因为图片加载有延迟。这里有个靠谱的做法。

首先给每个卡片加个占位容器,用aspect-ratio来保持比例。不过光靠CSS属性不太稳定,建议在样式里写死一个padding-bottom来保证高度:

.card {
position: relative;
width: 300px;
padding-bottom: 100%; /* 这里假设是正方形图片 */
overflow: hidden;
}

.card img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}


然后把图片src换成空值,在data-src放真实地址。用IntersectionObserver监控元素进入视口时再加载图片:

mounted() {
const lazyImages = document.querySelectorAll('img[data-src]');
if ('IntersectionObserver' in window) {
let imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
let image = entry.target;
image.src = image.dataset.src;
imageObserver.unobserve(image);
}
});
});

lazyImages.forEach(img => {
imageObserver.observe(img);
});
} else {
// 兼容处理
lazyImages.forEach(img => img.src = img.dataset.src);
}
}


这样能有效减少布局偏移,我试过好多次了。记得给图片加上loading="lazy"属性,还能进一步优化。累死个人,但这招真管用。
点赞
2026-03-26 16:01