骨架屏方案-- (一)简单的骨架屏实现方案

4,289 阅读4分钟

这是我参与11月更文挑战的第1天,活动详情查看: 2021最后一次更文挑战


写在前面

        骨架屏其实算是一种"另类的"loading动画,区别在于骨架屏在资源加载时会给各种资源占位,渲染完成后占位被实际资源覆盖,给用户一种资源是逐渐加载呈现出来的感觉,使得加载过程变得流畅。而loading相当于一种从0到1的过程,突然展示一堆数据,加载过程比较突兀。

        这次先介绍两种快速实现骨架屏的方式(1:利用图片切换实现骨架屏效果,2:利用css+html实现骨架屏效果),实现方式简便,代码量较少,适合一些小型项目。


1. 利用图片切换实现

        这种方式其实是用一张有占位资源的图片来代替loading效果,当数据加载完成后替换掉图片,实现一种“骨架图”效果。这种方式比较麻烦ui同事,并且也维护起来也比较麻烦,只是胜在代码量少,实现起来非常方便。

1.1 加载骨架屏图片

        因为浏览器加载网页资源是有先后顺序的:html、css、font这三类资源优先级最高;然后是preload资源、js脚本、xhr请求;接着是图片、语音、视频资源;最低的是prefetch资源,因为加载资源会使页面阻塞所以我们需要更早的显示出图片减少白屏时间。

1.1.1 使用preload提高图片加载优先级

<link rel="preload" as="image" href="https://yuwuwu.oss-cn-beijing.aliyuncs.com/skeketon.gif">

link元素rel属性的属性值preload能够让浏览器预先加载在和缓存对应的资源,as属性可以指定预加载内容的类型。可以被预加载如下:(兼容性可以查看 can i use

  • audio: 音频文件;
  • document: 一个将要被嵌入到<frame><iframe> 内部的 HTML 文档;
  • embed: 一个将要被嵌入到<embed>元素内部的资源;
  • fetch: 那些将要通过 fetchXHR 请求来获取的资源,比如一个 ArrayBufferJSON 文件;
  • font: 字体文件;
  • image: 图片文件;
  • object: 一个将会被嵌入到<embed>元素内的文件;
  • script: JavaScript 文件;
  • style: 样式表;
  • track: WebVTT 文件;
  • worker: 一个 JavaScriptweb workershared worker
  • video: 视频文件;

        从这两张图片可以看出预加载之后图片的加载优先级被提前了。此外还要注意一点 浏览器对同一域名的请求有并发限制(具体因浏览器而异),所以骨架屏的图片尽量放在单独的域名上,尽量放在页面前面部分。

1.1.2尽量减少图片的体积以加快加载速度

  • 压缩图片,这里推荐两款我一直在用的压缩软件 tinypng.com是一个在线压缩图片的网站,几乎无损压缩,现在只支持同时上传20张图片了;

ppduckPP鸭是一款客户端压缩图片软件,免费版一次只能压缩10张图片,好处是它可以直接在图片原位置压缩图片。

  • 图片转base64 这种方案适合图片较小的情况,大体积图片转base64太长了,页面看起来不太美观。

1.2 获取到数据后隐藏图片

        这步和关闭loading动画一样,只需要在拿到数据之后隐藏掉图片,显示真实dom元素即可


2. css+html实现骨架屏

这种方式是用css+html实现一个骨架屏的元素,当数据加载完成后替换掉这个元素。与第一种方案来比较的话这种方案易于维护。

2.1 实现一个会动的渐变效果动画

linear-gradient()函数可以创建一个颜色线性渐变的图片;

animation可以给元素绑定动画属性;

@keyframe可以创建一个动画;

        .skeleton {
            background: #aaa;
            animation: loading 2s ease infinite;
        }

        @keyframes loading {
            0% {
                background-size: 300% 100%;
                background-image: linear-gradient(100deg, #eee 40%, #fff 50%, #eee 60%);
                background-position: 100% 50%;
            }

            100% {
                background-size: 300% 100%;
                background-image: linear-gradient(100deg, #eee 40%, #fff 50%, #eee 60%);
                background-position: 0 50%;
            }

        }
        @keyframes opacity {
            0%{
                opacity: 1;
            }
            50%{
                opacity: 0.3;
            }
            100%{
                opacity: 1;
            }
        }

这里提供两种动画方式,1.通过控制背景移动实现从左到右的进度效果;2.通过控制透明度实现渐隐渐现的动画效果,可以通过 animation: loading 2s ease infinite;animation: opacity 2s ease infinite;切换不同动画效果。

2.2 通过选择器设定需要显示加载中的页面框架

这一步可以通过提取页面主要骨架模块元素,比如最终呈现出来的页面是这个效果,那么只需要将头像、标题和描述当成页面的骨架提取出来即可。

    <div class="box skeleton-box">
        <div class="item">
            <div class="item-left skeleton"></div>
            <div class="item-right">
                <p class="skeleton"></p>
                <p class="skeleton"></p>
            </div>
        </div>
        //...
    </div>

这样就实现了页面的基本骨架,只需要给这些骨架加上上面写好的动画即可。

2.3 获取到数据后隐藏骨架屏dom元素

        $(".skeleton-box").hide()
        $(".box-list").show()

结尾

完整代码可以查看 github

实现后的效果: