移动开发中更好的图片自适应
一直以来,我们在 PC 端开发中,都要求给图片写上一个宽高,以避免图片加载后造成的 reflow 。但在移动端开发中,为了能适配各种各样的屏幕尺寸,我们都不会像在PC端中一样给图片设定固定的宽高,美其名曰:响应式图片
。
一般做法是:
img{width: 100%;}
更好的写法是:
img{max-width: 100%;}
更好的写法好处是避免当图片尺寸小于屏幕尺寸时,拉伸造成图片失真,影响体验。
按上面的方式处理,图片就能根据屏幕大小自动等比缩放,达到响应式的效果。大多数情况下已经满足我们日常的开发需求,但在一些特殊需求里,如图片后面有内容,图片做按需加载,或者图片做一个进场动画,这时,当图片加载前和加载后,会造成 reflow
,在视觉体验上我们就看到内容在图片出来前后有一个跳动,一定程度上影响了我们的体验。作为一名新时代的切图仔,我们应该解决这个问题。
我们要的其实很简单,就是在不同屏幕大小,图片能等比缩放显示,单位 px
肯定是不行的了,我们需要一个相对的单位,上面的 %
是一个,但会有 reflow
问题。目前较好的选择是 rem
, 它是相对于根元素的相对单位,也就是说,如果我们根据屏幕等比动态地更新根节点的 font-size
值,通过 rem 就能自动更新图片的大小。所以,如下方案:
更好的自适应: js + rem
- JS 动态给 html 设置一个跟屏幕宽度成正比的 font-size
- 图片宽高用 rem 做单位
** 与屏幕宽度成正比的 font-size **
var docEl = document.documentElement;
docEl.style.fontSize = docEl.getBoundingClientRect().width / 16;
如上 JS ,我们用浏览器的默认字体大小作为基数(这里没有绝对关系,可以用任意数值)。
假设我们的设计稿是按 640 宽来设计的,图片为 600x300。 那么,得到的 font-size 是 40,也就是说,在样式里,我们需要将图片的宽高除以 40 转换成相应的 rem 单位,得到的值为 width: 15rem; height: 7.5rem
,在 iphone4 下效果如图:
图片显示的宽高为等比,测试链接: http://jsbin.com/qirifadiyu/1/
这样子,图片既能够自适应,又有大小,就不会有 reflow
造成的跳动现象。一切看起来很美好,但其实有一定限制。
** 限制: ** 按 640 宽来设计的页面,理论上我们切出来的图片不会大于 640,但如果一定要用大于 640 的图片,这样子换算后图片的宽度就会大于屏幕宽度,就达不到我们要的效果了。这时可以以屏幕宽度为基值,如 height = 图片高度 * 16 / 图片宽度。
完整的 JS 如下:
;(function(win){
var docEl = document.documentElement,
timer = null,
rem;
function setUnit(){
rem = docEl.getBoundingClientRect().width / 16;
docEl.style.fontSize = rem + 'px';
}
win.addEventListener('resize', function() {
clearTimeout(timer);
timer = setTimeout(setUnit, 300);
}, false);
win.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(timer);
timer = setTimeout(setUnit, 300);
}
}, false);
setUnit();
})(window);
纯CSS更好的解决方案
** html **
<div class="pic-wrap">
<img src="http://ww3.sinaimg.cn/mw690/69243898gw1emmeiydzvrj20go08cglu.jpg" alt=""/>
</div>
** css **
.pic-wrap{position: relative; padding-top: 50%;}
.pic-wrap img{position: absolute; left: 0; top: 0; width: 100%; max-width: 640px;}
此方法依赖于一定的结构,但相对于上一个方法来说,不需要依赖 JS。因为 padding 的百分比值是相对于宽度的,也就是有了跟屏幕宽度成正比的条件,所以利用 padding-top 设置与宽高等比的百分比值占位,就实现了同样的效果。
计算公式: padding-top: 图片高度 * 100% / 图片宽度。
测试链接: http://jsbin.com/cexazepuvi/1/