图片占位防闪烁

4,502 阅读3分钟

问题所在

ue给了这么一个设计稿

很简单,视频,按钮,上拉加载,懒加载,预加载各种逻辑很快就出现在脑海里了。但是简单无脑的开发完后,发现了一个很严肃的问题,所有视频和视频的poster都是异步请求加载的,也就意味着之前的dom节点是没数据或者根本没加载和宽高的。从而屏幕一刷新就开始闪烁。相信很多人遇到过,所以在这里写一个方案来解决。

补充

网上有人发了一张这类问题更形象的图:

当图片加载慢的时候

解决方案

采用padding或者margin来做内容撑开。

先介绍一个知识点:padding和margin采取百分比形式的时候,他的值是以父容器的宽度为标准的。以padding为例,padding-left、padding-right、padding-top和padding-bottom,都以父容器的宽度为基准。如果父容器宽度是100px,那么你padding-bottom:50%的值就是50px。这里有个前提就是当前的布局流为horizontal-flow形式。如果当前布局流是vertical-flow,那么padding百分比的参照基准就变成父容器的高度了。 这是我找到能稍微介绍下什么是horizontal-flow和vertical-flow的知识了,也可能理解有误,期望能评论中告诉我什么是horizontal-flow和vertical-flow,期盼。。。

pc端一般不需要考虑,写死宽高没问题。但是移动端手机屏幕和像素各不相同,很少有用固定像素去做定位,基本都是百分比。我们正常一张图片的宽度为父容器的30%,那么高度按期宽高比去计算,就知道一张图片的高度是多少了。按第一张设计图来说,每张图片的宽高比我是知道的。例如高 / 宽 = 404 / 346。那么可以利用父容器宽度确定,自己宽度和高度的基准都是基于父容器的宽度,那么很容易计算或者说获取到自己应该有多少高度,然后使用padding这个撑开一个div,占住这个位置,然后等图片刷新出来,这样就能避免页面不再闪烁。

<body>
         <div class='father'>
            <div>
                <div class='first-kid'>
                    <!-- <div class='test'> -->
                    <div class='placeholder'></div>
                    <!-- </div> -->
                    <!-- <div class='img'></div> -->
                </div>
                <div>123</div>
            </div>
         </div>
    </body>
.father {
    width: 1000px;
    height: 1000px;
    border: 1px solid black;
    .first-kid {
        width: 20%;
        max-width: 22%;
        min-width: 18%;
        position: relative;
        background: red;
        .test {
            width: 100%;
        }
        .placeholder {
            padding-bottom: 100%;
        }
        .img {
            width: 100%;
            height: 100%;
            background-image: url(https://wx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoBsnPv96dia8wxrWu5zXD2bd3bvrPOlh4zDO6WjhraYM9Fo1affszOYhnqDcGNOmj0gwpBkvZdDTQ/132);
            background-size: cover;
            background-position: 50% 50%;
            position: absolute;
            top: 0;
        }
    }
}

图片我已经放在里面了,只不过进行了注释。如果兴趣的“掘墓人”们可以放开试一下。当然,这里采用的是用里面一个空的div元素去撑开父容器,相当于占位符的。后来看b站有的做法更值得使用,因为他的盒子模型更加符合语义。

html代码不变,只改动css。采用的是伪类的方式来解决,从浏览器去解析起来,更语义化。

.father {
    width: 1000px;
    height: 1000px;
    border: 1px solid black;
    .first-kid {
        width: 20%;
        max-width: 22%;
        min-width: 18%;
        position: relative;
        background: red;
        // .test {
        //     width: 100%;
        // }
        // .placeholder {
        //     padding-bottom: 100%;

        // }
        .img {
            width: 100%;
            height: 100%;
            background-image: url(https://wx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoBsnPv96dia8wxrWu5zXD2bd3bvrPOlh4zDO6WjhraYM9Fo1affszOYhnqDcGNOmj0gwpBkvZdDTQ/132);
            background-size: cover;
            background-position: 50% 50%;
            position: absolute;
            top: 0;
        }
    }
    .first-kid:after {
        content: '';
        display: block;
        padding-bottom: 100%;
    }
}

后续

诸位如果有兴趣,可以琢磨一下css3的长度单位vw,将宽高的值单位全部设置成vw也能很好解决高度不确定问题,但是css3的兼容问题值得注意,如果你们的项目确定用的是这些版本,可以使用,非常好玩。