Image Reserved Placeholder and Display Optimization on HTML Page
公司的Web项目,处理图片延迟加载时,遇到一个图片预留占位的显示问题。记录一下相关解决方案。
1. 需求
本来要解决的问题是,图片“延迟加载”。然后图片未加载之前,需要预留占位,避免加载后撑大页面(主要是为了更好看吧)。
2. 解决方案
图片延迟加载,使用<img>
的loading="lazy"
即可。现代浏览器,当前对其支持还不错。另外,最好不用使用CSS的background
加载图片,因为没有很好(或者说简单)的延迟加载解决方案。
对于图片预留占位,主要根据界面设计的布局,选择不同的处理方法。比较麻烦的是,需要自适应浏览器窗口大小的情况。如下:
- 已知图片宽高。可以随便整。
- 图片框固定大小。使用CSS的
object-fit
获得最佳显示效果。 - 固定列数的图片框自适应浏览器窗口。按浏览器窗口自动计算图片框的宽度。
- 图片框宽度自适应。使用动态的正方形图片框。这是最终采用的方案。
2.1. 已知图片宽高
可以设置图片按比例缩放,或者按最长边等比例缩放。这个不用说了。
2.2. 图片框固定大小
例如图片框固定,宽为300px,高为300px。图片保持比例,并完整显示,使用CSS的object-fit:contain;
。代码如下:
<div style="width:300px; height:300px;">
<img src="..." style="width:100%; height:100%; object-fit:contain;" />
</div>
2.3. 固定列数的图片框自适应浏览器窗口
一般是列表中带图片的情况,可以使用CSS的单位vw
和vh
。
- vw,浏览器窗口宽度的1%
- vh,浏览器窗口高度的1%
关于CSS的长度单位,详见:
缺点:
- 如果图片的宽高,不能根据屏幕的宽高计算出来,此方案不适用。
- 如果图片宽高不能适应图片框的比例,也是使用
object-fit:contain;
按比例缩放。
以下示例,按4列显示,图片框是宽高都为窗口宽度24%的正方形:
<style>
body{margin:0; padding:0;}
.ItemList{width:100%; margin:0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; justify-content: space-evenly;}
.ItemWrap{width:24%; margin:1vw 0 0; padding:0; display: block;}
.ItemWrap img{width:24vw; height:24vw; object-fit: contain;}
</style>
<ul class="ItemList">
<li class="ItemWrap"><img src="..." loading="lazy" /></li>
<li class="ItemWrap"><img src="..." loading="lazy" /></li>
<li class="ItemWrap"><img src="..." loading="lazy" /></li>
<li class="ItemWrap"><img src="..." loading="lazy" /></li>
<li class="ItemWrap"><img src="..." loading="lazy" /></li>
<li class="ItemWrap"><img src="..." loading="lazy" /></li>
<li class="ItemWrap"><img src="..." loading="lazy" /></li>
<li class="ItemWrap"><img src="..." loading="lazy" /></li>
</ul>
2.4. 图片框宽度自适应
动态宽高的正方形图片框,是比较折中和灵活的方案。可以不用知道图片宽高。图片框宽度动态计算,高度设为跟高度一致。示例如下:
<style>
body{margin:0; padding:0;}
.ItemList{width:100%; margin:0; padding:0; list-style:none; display:flex; flex-wrap:wrap; justify-content:space-evenly;}
.ItemWrap{width:24%; margin:1vw 0 0; padding:0; display:block; background-color:#c5a29c;}
.ImgWrap{width:100%; height:0; padding-bottom:100%; overflow:hidden; display:block; position:relative;}
.ImgWrap img{width:100%; height:100%; object-fit:contain; position: absolute;}
</style>
<ul class="ItemList">
<li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
<li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
<li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
<li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
<li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
<li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
<li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
<li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
</ul>
解析:
ul
标签,使用灵活的flex
样式显示列表。li
标签,决定列数。a
标签,作为图片框,限制图片显示的宽高。a
标签的height:0; padding-bottom:100%;
,通过padding-bottom
设置高度与宽度一致,是这个方案最巧妙的地方。a
标签的overflow:hidden;
,避免内嵌的图片溢出。a
标签的position:relative;
,把宽高传给子级。img
标签,通过position: absolute;
悬浮显示在图片框上面,其宽高获取了图片框(即父级)的宽高。
3. 后续问题
图片加载时,小图最好加载对应的缩略图。体积小,加载快,体验好。但是要考虑图片框大小,避免小图被拉大而导致模糊,降低用户观感。