Placeholder占位加载时布局会跳动怎么办?

シ樱潼 阅读 14

我在用Vue做列表加载,数据没回来前用灰色块当placeholder,但真实数据渲染后高度变了,页面会突然跳一下,体验很差。试过固定高度但内容长短不一不好设。

现在代码是这样:

<div v-for="item in loading ? placeholders : items" :key="item.id">
  <div class="skeleton" v-if="loading"></div>
  <div class="content" v-else>{{ item.text }}</div>
</div>

有没有办法让占位和真实内容高度一致,或者用其他方式避免布局偏移?

我来解答 赞 9 收藏
二维码
手机扫码查看
1 条解答
轩辕炜曦
这个问题太常见了,就是典型的CLS(累积布局偏移)。

核心思路是让 skeleton 的高度跟真实内容尽可能一致。你现在的问题是把 skeleton 写成了一个简单的灰色块,高度当然对不上。

最简单的解决办法:让 skeleton 模拟真实内容的结构。

<div v-for="item in loading ? placeholders : items" :key="item.id">
<div class="skeleton" v-if="loading">
<div class="skeleton-avatar"></div>
<div class="skeleton-text">
<div class="skeleton-line"></div>
<div class="skeleton-line short"></div>
</div>
</div>
<div class="content" v-else>
<img :src="item.avatar" />
<p>{{ item.text }}</p>
</div>
</div>


.skeleton {
display: flex;
gap: 12px;
padding: 16px;
}

.skeleton-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: #eee;
}

.skeleton-text {
flex: 1;
}

.skeleton-line {
height: 16px;
background: #eee;
border-radius: 4px;
margin-bottom: 8px;
}

.skeleton-line.short {
width: 60%;
}


这样 skeleton 的结构和真实内容一致,高度自然就对了。内容长短不一的问题也能cover,因为你是按行模拟的,最多就是最后一行短一点,视觉上几乎看不出差别。

如果你是纯文本没图片,那就更简单了,直接按行数来:

.skeleton {
min-height: 80px; /* 假设最多4行,每行20px + padding */
}


或者动态计算:后端返回数据的时候顺便返回个预估高度字段,前端直接用来设 skeleton 的 min-height。

说白了就是别偷懒让 skeleton 只是一个简单的 div,把它的dom结构写成跟真实内容一样的,自然就不跳了。
点赞
2026-03-18 19:00