认识 Skeleton Screen 屏幕加载骨架

发布于 2022-10-14 21:17:59 字数 11496 浏览 139 评论 0

一直以来,无论是 Web 还是 iOS、android 的应用中,为了提升应用的加载等待这段时间的用户感知体验,各种奇门遁甲之术层出不穷。其中,菊花图以及由它衍生各种加载动画是一个非常大的流派,如下图所示:

 

由它衍生而出的各种加载动画也是遍地开花:

在很多的应用的交互中,这种菊花的加载的设计已然要一统江湖了。

不过,现在对于加载的设计体验有了比菊花加载体验更棒的方法,即本文要讲的 Skeleton Screen Loading,中文一般叫做骨架屏。骨架屏听起来总觉得怪怪的,本文还是沿用英文的叫法 Skeleton Screen Loading。

所谓 Skeleton Screen Loading 即表示在页面完全渲染完成之前,用户会看到一个样式简单,描绘了当前页面的大致框架,感知到页面正在逐步加载,加载完成后,最终骨架屏中各个占位部分将被真实的数据替换。

一图胜千言,来看看微信阅读的客户端,它就使用了 Skeleton Screen Loading 来提升它的加载体验,可以下载它的客户端实际感受下:

现在好多 Web 和客户端都已经放弃了以前的那种菊花的加载体验,转而使用 Skeleton Screen Loading,比如 Facebook、medium 以及 slack 等。国内的饿了么、掘金等也都使用 Skeleton Screen Loading 来提升它们的加载体验。

下面这段话,是iOS中关于加载体验的交互设计标准的一个说明:

Don’t make people wait for content to load before seeing the screen they’re expecting. Show the screen immediately, and use placeholder text, graphics, or animations to identify where content isn’t available yet. Replace these placeholder elements as the content loads. — Apple iOS Human Interface Guidelines

使用Skeleton Screen Loading也充分遵循了iOS人机交互设计指南。本文就来讲讲如何使用vue来实现Skeleton Screen Loading。

VUE实现思路

在本文中,我们将会使用vue组件 (Component) 功能来实现一个Skeleton Screen Loading,如下图所示:

具体 Vue 组件 (Component) 功能这里就不详讲了,可以去 官方的文档 看看详细的信息。

这里推荐一个模拟开发数据的开源服务 jsonplaceholder,类似经常使用的图片占位服务一样,它提供了在 Web 开发中一些常见数据类型的 api 服务,比如文章、评论、用户系统等,都提供了对应的接口,在开发调试阶段还是非常方便的。

比如我们做的这个例子要用到用户系统,直接使用这个 用户数据接口 就行了。

首先,主要的工作是实现 Skeleton Screen Loading 加载动画,先使用常规的 html 和 css 来实现这个动画。

动画效果如下所示:

先定义好 html 结构:

<div class="timeline-item">
   <div class="animated-background">
     <div class="background-masker header-top"></div>
     <div class="background-masker header-left"></div>
     <div class="background-masker header-right"></div>
     <div class="background-masker header-bottom"></div>
     <div class="background-masker subheader-left"></div>
     <div class="background-masker subheader-right"></div>
     <div class="background-masker subheader-bottom"></div>
   </div>
</div>

下面来说说实现动画的主要思路:

要实现这样的效果,需要使用一点点小技巧。先在图层 animated-background 定义一个大的渐变背景,然后在不需要显示背景图的位置,定义几个占位的结构填充为白色就可以实现上图所示的UI展现形式。最后使用 background-position 来移动背景图片的位置,就可以实现图中的动画效果。

详细的代码可以去这里查看 demo

主要的效果实现了,下面就可以正式开工来定义我们的 Skeleton Screen Loading 组件。

Vue.component('user-item', {
  props: ['email', 'name'],
  template: `<div>
      <h2 v-text="name"></h2>
      <p v-text="email"></p>
    </div>`
})

Vue.component('loading-item', {
  template: `<div class="animated-background">
     <div class="background-masker header-top"></div>
     <div class="background-masker header-left"></div>
     <div class="background-masker header-right"></div>
     <div class="background-masker header-bottom"></div>
     <div class="background-masker subheader-left"></div>
     <div class="background-masker subheader-right"></div>
     <div class="background-masker subheader-bottom"></div>
   </div>`
})

上面定义了两个组件,一个是用来显示用户信息数据的组件 user-item;一个在加载完之前来显示 Skeleton Screen Loading 效果的 loading-item 组件。

定义好组件后,然后在主文件定义好对应的结构来注册使用组件:

<div>
  <div v-for="user in users" class="items" v-if="loading">
    <user-item :name="user.name" :email="user.email"></user-item>
  </div>
  <div v-for="load in loades" v-if="!loading">
    <loading-item></loading-item>
  </div>
</div>

根据上面定义好的组件,上面的代码表示,当数据加载完后,显示用户数据。当还没有加载完用户数据,则显示预先定义好的加载组件即 loading-item。

var app = new Vue({
  el: '#app',
  data: {
    users: [],
    loading: false,
    loades: 10
  },
  methods: {
    getUserDetails: function() {
      fetch(`https://jsonplaceholder.typicode.com/users`)
        .then(result => result.json())
        .then(result => {
          this.users = result
          this.loading = true
        });
    }
  },
  created: function() {
    setTimeout(() => {
      this.getUserDetails()
    }, 1000);
  }
});

一个简单优雅的 Skeleton Screen Loading 就完成了。

Vue 版本:

<template>
  <div>
    <div class="cardList" v-for="n in 7">
      <div class="list">
        <div class="banner"></div>
        <div class="mvcont">
          <div class="mvnema"></div>
          <div class="performer"></div>
          <div class="details"></div>
          <div class="ftcon"></div>
        </div>
        <div class="hband"></div>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    components: {},
    methods: {

    },
    mounted() {

    },
    created() {

    }
  };
</script>

<style scoped="scoped" lang="scss">
  @keyframes placeHolderShimmer {
    0% {
      background-position: -414px 0;
    }
    100% {
      background-position: 414px 0;
    }
  }
  
  .cardList {
    background: white;
    position: relative;
    .list {
      box-sizing: border-box;
      margin: .24rem .24rem;
      overflow: hidden;
      display: flex;
      justify-content: flex-start;
      align-items: center;
      background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
      animation: placeHolderShimmer 1.5s linear 0s infinite forwards;
      .banner {
        width: 1.18rem;
        height: 1.60rem;
      }
      .mvcont {
        box-sizing: border-box;
        flex: 1;
        width: 100%;
        height: 1.60rem;
        position: relative;
        &::before {
          content: "";
          position: absolute;
          top: 0px;
          left: 0px;
          width: 0.17rem;
          height: 100%;
          background: white;
        }
        &::after {
          top: 0px;
          right: 0px;
          content: "";
          position: absolute;
          width: 0.17rem;
          height: 100%;
          background: white;
        }
        .mvnema {
          position: relative;
          width: 100%;
          height: 0.5rem;
          &::before {
            content: "";
            position: absolute;
            top: 0px;
            left: 0px;
            width: 100%;
            height: 0.1rem;
            background-color: white;
          }
          &::after {
            content: "";
            position: absolute;
            top: 0px;
            right: 0px;
            width: 40%;
            height: 0.5rem;
            background-color: white;
          }
        }
        .performer {
          position: relative;
          width: 100%;
          height: 0.4rem;
          color: #333333;
          &::before {
            content: "";
            position: absolute;
            top: 0px;
            left: 0px;
            width: 100%;
            height: 0.1rem;
            background-color: white;
          }
          &::after {
            content: "";
            position: absolute;
            top: 0px;
            right: 0px;
            width: 5%;
            height: 0.4rem;
            background-color: white;
          }
        }
        .details {
          position: relative;
          width: 100%;
          height: 0.6rem;
          &::before {
            content: "";
            position: absolute;
            top: 0px;
            left: 0px;
            width: 100%;
            height: 0.3rem;
            background-color: white;
          }
          &::after {
            content: "";
            position: absolute;
            top: 0px;
            right: 0px;
            width: 30%;
            height: 0.6rem;
            background-color: white;
          }
        }
        .ftcon {
          width: 100%;
          height: 0.4rem;
          background: white;
        }
      }
      .hband {
        border-radius: 0.04rem;
        width: 1.28rem;
        height: 1.60rem;
        position: relative;
        &::before {
          content: "";
          position: absolute;
          width: 100%;
          height: 0.51rem;
          top: 0px;
          left: 0px;
          background: white;
        }
        &::after {
          content: "";
          position: absolute;
          width: 100%;
          height: 0.51rem;
          bottom: 0px;
          left: 0px;
          background: white;
        }
      }
    }
  }
</style>

通过上面简单的实例,可以明显感受到当使用 Skeleton Screen Loading 来代替传统的菊花图在体验上更加好一些。

使用 Skeleton Screen Loading,可以利用一些视觉元素来将内容的轮廓更快显示在屏幕上,让用户在等待加载的过程中对将要加载的内容有一个更加清晰的预期,特别是在弱网络的场景下,Skeleton Screen Loading 的体验无疑是更好的,用起来吧。

对于 Skeleton Screen Loading,你有什么样的看法呢?欢迎在评论区留言一起分享你的看法。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

谷夏

暂无简介

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文