移动开发中更好的图片自适应

一直以来,我们在 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 下效果如图:

Alt text

图片显示的宽高为等比,测试链接: 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/

参考文档

手机淘宝的flexible设计与实现

posted @ 2014-12-17 12:19  肥杜  阅读(2248)  评论(0编辑  收藏  举报