b站首页视频在后端接口返回来数据之前会有时间间隔,为了提高页面的加载等待这段时间的用户感知体验,在数据赋值上去之前会有动画加载骨架。说白了,就是在数据回来之前先用一些好看的动画顶着,占着那片地,很多其他官网也是如此。
效果
-
具体效果如下:
-
没有数据,单独看效果时
- 加上请求数据,看整体效果时
原理
原理其实就是,在主长方形里面,用一个
同样大小或者比这个主框大的元素背景色是线性渐变,用动画的形式从左到右移动。
代码
多说无益,上代码
架构
<div>
// 背景图的框
<div class="pic-card">
<picture>
<img src="" alt="" />
</picture>
</div>
// 标题框
<div class="pic-description">
<div class="title"></div>
</div>
// 昵称框
<div class="pic-description">
<div class="title content"></div>
</div>
</div>
css
<style>
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.pic-card, .pic-description {
position: relative;
width: 280px;
height: 150px;
border-radius: 6px;
}
picture, .title {
background-color: #F1F2F3;
position: absolute;
top: 0;
left: 0;
z-index: 1;
overflow: hidden;
width: 100%;
height: 100%;
object-fit: contain;
border-radius: inherit;
}
picture:before, .title::before {
animation: image_loading 1s cubic-bezier(0.4, 0, 0.2, 1) infinite; // 动画
background: linear-gradient(-45deg, #F1F2F3 25%, #FFFFFF 45%, #F1F2F3 65%); // 线性渐变背景
bottom: -20%;
content: "";
display: block;
height: 140%;
left: 0;
position: absolute;
top: -20%;
width: 100%;
}
.pic-description {
margin-top: 10px;
width: 260px;
height: 20px;
}
.content {
width: 200px;
}
// 动画 从左到右
@keyframes image_loading {
0% {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
to {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
}
</style>
vue3 + 数据
加上数据这一步,就看数据出来之后,1、把背景色灰色搞掉;2、把移动的那个线性渐变的框搞掉;这两点就完事了。
<template>
<div class="main">
<div class="pic-card">
<picture class="skeleton">
<div v-if="data.loading" class="cover"></div>
<img v-if="!data.loading && data.url" :src="data.url" alt="" />
</picture>
</div>
<div class="description">
<div class="skeleton title" :class="{ white: !data.loading }">
<div v-if="data.loading" class="cover"></div>
<div v-else>求求你给我一个认识你的机会呜呜</div>
</div>
</div>
<div class="description">
<div class="skeleton content" :class="{ white: !data.loading }">
<div v-if="data.loading" class="cover"></div>
<div v-else>紫菜蛋花兔兔</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, reactive } from "vue";
const data = reactive({
loading: true,
url: "",
});
const fakeApi = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 5000);
});
};
const getList = async () => {
data.loading = true;
await fakeApi();
data.loading = false;
data.url =
"https://i0.hdslb.com/bfs/live/user_cover/bf8980244ea0230d5a7679445ad1c75c36e31afd.jpg@672w_378h_1c_!web-home-common-cover.avif";
};
onMounted(() => {
getList();
});
</script>
quora 图片加载动画
<div class="father">
<div class="fyplfD" style="box-sizing: border-box; aspect-ratio: 16 / 9; margin-left: -16px; margin-right: -16px;"></div>
</div>
// css 代码
@keyframes image_loading {
0% {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
to {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
}
.father {
width: 500px;
height: 250px;
background-color: rgb(241, 242, 242);
overflow: hidden;
}
.fyplfD {
animation: 1.2s linear 0s infinite normal forwards running image_loading;
background-size: 200% 100%;
background-repeat: repeat;
background-color: rgb(241, 242, 242);
background-image: linear-gradient(100deg, rgb(241, 242, 242) 5%, rgb(228, 230, 230) 20%, rgb(241, 242, 242) 35%);
}
效果