移动端开发自适应解决方案(阿里团队高清方案)

研究m端开发自适应有一段时间了,下面做一个总结
移动端自适应方案有很多种
1.流式布局


也就是固定高度,宽度使用百分比的方法,这种方法会导致一些元素在大屏手机上拉伸严重的情况,影响视觉效果,只有在很少一部分手机上能完美的展示设计师想要的效果。携程之前用的就是流式布局,但之后也改版了。
2.固定宽度做法


比如早期的淘宝webpage,页面设置成320的宽度,超出部分留白,在大屏幕手机上,就会出现两条大百边,分辨率高的手机,页面看起来就会特别小,按钮,文字也很小,之后淘宝改了布局方案,也就是接下来要讲的rem布局,

3.响应式做法

用一些css框架,比如bootstrap,或者jqueryUI,使用媒体查询,这种方式维护成本高,很少有大型网站使用这种布局(据说的)

4.设置viewport进行缩放

天猫的web app的首页就是采用这种方式去做的,以320宽度为基准,进行缩放,最大缩放为320*1.3 = 416,基本缩放到416都就可以兼容iphone6 plus的屏幕了,这个方法简单粗暴,又高效。说实话我觉得他和用接下去我们要讲的rem都非常高效,不过有部分同学使用过程中反应缩放会导致有些页面元素会糊的情况。

5.rem布局

rem是css3新引入的单位,在pc端会有兼容性的问题,对移动端比较友好。简而言之就是通过动态设置html根元素的fontsize,等比缩放元素大小来自适应移动设备。

翻了很多资料,po也测试过最好用省事的就是rem布局 ,rem布局也有新旧版,这里讲最普用的阿里团队的高清方案,也是现在淘宝m端使用的解决方案。
以下是核心js代码

! function(e) {
    function t(a) {
        if (i[a]) return i[a].exports;
        var n = i[a] = {
            exports: {},
            id: a,
            loaded: !1
        };
        return e[a].call(n.exports, n, n.exports, t), n.loaded = !0, n.exports
    }
    var i = {};
    return t.m = e, t.c = i, t.p = "", t(0)
}([function(e, t) {
    "use strict";
    Object.defineProperty(t, "__esModule", {
        value: !0
    });
    var i = window;
    t["default"] = i.flex = function(e, t) {
        var a = e || 100,
            n = t || 1,
            r = i.document,
            o = navigator.userAgent,
            d = o.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i),
            l = o.match(/U3\/((\d+|\.){5,})/i),
            c = l && parseInt(l[1].split(".").join(""), 10) >= 80,
            p = navigator.appVersion.match(/(iphone|ipad|ipod)/gi),
            s = i.devicePixelRatio || 1;
        p || d && d[1] > 534 || c || (s = 1);
        var u = 1 / s,
            m = r.querySelector('meta[name="viewport"]');
        m || (m = r.createElement("meta"), m.setAttribute("name", "viewport"), r.head.appendChild(m)), m.setAttribute("content", "width=device-width,user-scalable=no,initial-scale=" + u + ",maximum-scale=" + u + ",minimum-scale=" + u), r.documentElement.style.fontSize = a / 2 * s * n + "px"
    }, e.exports = t["default"]
}]);
flex(100, 1); 

代码原理:

1.根据设备屏幕的DPR(设备像素比,比如dpr=2时,表示1个CSS像素由2X2个物理像素点组成) 动态设置 html 的font-size
2.同时根据设备DPR调整页面的缩放值,进而达到高清效果。

方案优势:

1.引用简单,布局简便(只要把js代码贴到head标签里面,就可以使用了,设计稿一般是640 或者750的,不需要进行单位换算,直接用设计稿的尺寸就可以,比如设计稿上有一个btn的高度为80px,宽度为120px,高清方案默认1rem=100px,那么 btn的宽度就设置为:)

.btn {
    width:0.8rem
    height:1.2rem
}

2.根据设备屏幕的DPR,自动设置最合适的高清缩放。保证了不同设备下视觉体验的一致性。
旧方案,屏幕越大,元素也越大,新方案,屏幕越大,看到的越多
看得越多的理解:
比如,一篇很长的文章在ip4上,一屏盛不了那么多内容,而在ip6plus上,可以全部看清楚,这是因为,新方案会根据dpr来缩放视口,大屏小屏的手机上,显示的字体大小都是一致的,当然在大屏上看到的东西就多咯~
3.有效解决移动端真实1px问题(这里的1px 是设备屏幕上的物理像素)

注意

并不是所有用px的地方都要用rem,rem布局只针对固定宽度。

依需求而定,比如淘宝页面底下的tabar,和头部搜索区域,都是用百分比来布局的,或者flex和模型,当在ipad上打开的时候就可以看见,头部和tab是撑满全屏的。
中间的主要内容(最外部的容器)要设置一个max-width,demo设置的是max-width:10rem,这里我不太明白为什么要设置成10rem,有弄明白的小伙伴希望能告诉我。谢谢(已解决,和设置最外层宽度为100%是一样的道理,10rem 可以适配到所有手机设备。1000%可以适配ipad,demo试试就知道了)
(应用了此方案,不管设计图多宽(当然,一般宽度为750,640也可以),最外层的div宽度设为100%就行,然后就可以愉快的布局了,不会出现你说的白边的情况。)

对于尺寸比较大的元素,应该考虑用百分比。rem做单位的元素在哪种设备下都是固定大小,这点必须牢记!!

可能遇到的问题

1.问:为啥手机网页效果图宽度是要640或者750的,我非得弄个666的不行咩?

答:老实说当然可以,不过为了规范,640或者750是相对合适的。拿Iphone 5s 举例,它的css像素宽度是320px,由于它的dpr=2,所以它的物理像素宽度为320 × 2 = 640px,这也就是为什么,你在5s上截了一张图,在电脑上打开,它的原始宽度是640px的原因。那 iphone 6 的截图宽度呢? 375 × 2 = 750那 iphone 6 sp 的截图宽度呢? 414 × 3 = 1242以此类推,你现在能明白效果图为什么一般是 640 ,750 甚至是 1242 的原因了么?(真没有歧视安卓机的意思。。。)

2.问:宽度用rem写的情况下, 在 iphone6 上没问题, 在 iphone5上会有横向滚动条,何解?

答:假设你的效果图宽度是750,在这个效果图上可能有一个宽度为7rem(高清方案默认 1rem = 100px)的元素。我们知道,高清方案的特点就是几乎完美还原效果图,也就是说,你写了一个宽度为 7rem 的元素,那么在目前主流移动设备上都是7rem。然而,iphone 5 的宽度为640,也就是6.4rem。于是横向滚动条不可避免的出现了。怎么办呢? 这是我目前推荐的比较安全的方式:如果元素的宽度超过效果图宽度的一半(效果图宽为640或750),果断使用百分比宽度,或者flex布局。就像把等屏宽的图片宽度设为100%一样。

3.问:不是 1rem = 100px吗,为什么我的代码写了一个宽度为3rem的元素,在电脑端的谷歌浏览器上宽度只有150px?

答:先说高清方案代码,再次强调咱们的高清方案代码是根据设备的dpr动态设置html 的 font-size,如果dpr=1(如电脑端),则html的font-size为50px,此时 1rem = 50px如果dpr=2(如iphone 5 和 6),则html的font-size为100px,此时 1rem = 100px如果dpr=3(如iphone 6 sp),则html的font-size为150px,此时 1rem = 150px如果dpr为其他值,即便不是整数,如3.4 , 也是一样直接将dpr 乘以 50 。
再来说说效果图,一般来讲,我们的效果图宽度要么是640,要么是750,无论哪一个,它们对应设备的dpr=2,此时,1 rem = 50 × 2 = 100px。这也就是为什么高清方案默认1rem = 100px。而将1rem默认100px也是好处多多,可以帮你快速换算单位,比如在750宽度下的效果图,某元素宽度为53px,那么css宽度直接设为53/100=0.53rem了。
然而极少情况下,有设计师将效果图宽定为1242px,因为他手里只有一个iphone 6 sp (dpr = 3),设计完效果图刚好可以在他的iphone 6 sp里查看调整。一切完毕之后,他将这个效果图交给你来切图。由于这个效果图对应设备的dpr=3,也就是1rem = 50 × 3 = 150px。所以如果你量取了一个宽度为90px的元素,它的css宽度应该为 90/150=0.6rem。由于咱们的高清方案默认1rem=100px,为了还原效果图,你需要这样换算。当然,一个技巧就是你可以直接修改咱们的高清方案的默认设置。在代码的最后 你会看到 flex(100, 1) ,将其修改成flex(66.66667, 1)就不用那么麻烦的换算了,此时那个90px的直接写成0.9rem就可以了。

4.问:高清方案在微信上,有时候字体会不受控制变的很大,怎么办?

答:参考
5.问:我在底部导航用的flex感觉更合适一些,请问这样子混着用可以吗?

答:咱们的rem适合写固定尺寸。其余的根据需要换成flex或者百分比。源码示例中就有这三种的综合运用。
6.问:在高清方案下,一个标准的,较为理想的宽度为640的页面效果图应该是怎样的?

7.这个会和bootstrap冲突。
解决办法:
1,将bootstrap 中,凡是用到px的单位一律换成rem
2,如果你有使用webpack,建议使用将css转成rem的包(postcss-pxtorem)将自动完成第一步的操作。

8.@2x和@3x的图片还要判断不同的dpr下用不同的图片。

Normalize.css 是一个可以定制的CSS文件,它让不同的浏览器在渲染网页元素的时候形式更统一。

Normalize.css 能干什么:

保留有用的默认值,不同于许多 CSS 的重置

标准化的样式,适用范围广的元素。

纠正错误和常见的浏览器的不一致性。

一些细微的改进,提高了易用性。

使用详细的注释来解释代码。

支持的浏览器:

Google Chrome (latest)

Mozilla Firefox (latest)

Mozilla Firefox ESR

Opera (latest)

Apple Safari 6+

Internet Explorer 8+

推荐阅读更多精彩内容