zoukankan      html  css  js  c++  java
  • 移动端适配之懒适配

    关于移动端的适配方案,现在其实已经有很多了,什么百分比、font-size+rem、视窗单位(vw、vh)等等,在介绍懒适配之前,先说说我常用的百分比吧。

    百分比布局

      元素的size:页面上的元素的width都使用百分比来实现,比如一行三列,每列就是33.33%,高度可以基于padding-bottom来实现,也可以让内部元素来支撑,这个主要看需求。

      字体大小:这个一般使用px,根据设计图来进行修改,最小12px

      整体页面:设置一个max-width,然后居中显示

      上面差不多就是百分比布局的一些要点,这其中有关size的都需要根据设计图来缩放,计算量还是挺大的,主要是太麻烦。。

    灵感来源

      懒适配的灵感来源是看了淘宝的适配方案,使用viewport来对页面进行缩放,但淘宝的适配不仅仅依赖于此,在这里就不展开了。

    viewport

      <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no,target-densitydpi=device-dpi" />

      解释一下上面这个viewport的作用吧,width=device-width,视窗的width为设备的width。initial-scale=1,初始化的缩放为1(相当于什么都不干)。user-scalable=no,禁止用户手动去缩放(在某些安卓上没有作业)。target-densitydpi=device-dpi,去兼容安卓低版本不支持缩放的问题。

    思路

      使用viewport来进行缩放,缩放的计算公式,设备的可视宽度/设计图的宽度,还有一些兼容和web的处理移动端需要使用meta来缩放,web端需要使用zoom来缩放

      移动端使用meta来进行缩放,因为考虑到需要适配web端,所以必须使用zoom来兼容

      页面所有元素都需要按照设计图来固定size,因为缩放也是安装设计图来进行缩放的

      在开发的过程中遇到android4.4以下和魅族的某些手机使用meta缩放有一些问题,所以这些情况也使用zoom配合target-densitydpi=device-dpi来进行缩放

      对ios设备在手机触发orientationchange事件,screen获取差异进行处理。

      在orientationchange的回调里增加一个定时器,解决某些低端安卓机获取可视区信息延迟的问题

    代码

    不解释了,直接上代码和注释吧

    /*这种设计模式下,移动端需要使用meta来缩放,web端需要使用zoom来缩放
                      页面所有元素都必须按照设计图的尺寸来固定
                  web端的缩放比例,预计的显示宽度/设计图的宽度
                  android 4.4以下对viewport缩放支持不太好,使用zoom配合target-densitydpi=device-dpi来缩放
                      魅族手机使用viewport缩放有点问题,需要使用上面的方法处理
                      
                      手机旋转时,android系浏览器和safari获取视窗的不同
                      
                      假如android和safari的size都是320*640
                      
                      在竖屏模式下   window.screen.width  window.screen.height
                      android        320                  640
                      safari         320                  640
                      
                      在横屏模式下   window.screen.width  window.screen.height
                      android        640                  320
                      safari         320                  640
                      在orientationchange的回调里增加一个定时器,解决某些低端安卓机获取可视区信息延迟的问题
                 **/
    function scale(deWidth,webWidth){//deWidth设计图的宽度,webWidth兼容web页面的宽度,项目在web需要显示的宽度(不能超过deWidth)
        var changeTimer = null,sWidth = window.screen.width;
        if(/iPhone|iPad|iPod/.test(navigator.userAgent)&&typeof window.orientation!=="undefined"&&window.orientation !== 0){
            sWidth = window.screen.height;
        }
        if(navigator.userAgent.indexOf("Mobile")!==-1){
            window.onorientationchange = function(){
                changeTimer&&clearTimeout(changeTimer);
                changeTimer = setTimeout(function(){
                    if(/iPhone|iPad|iPod/.test(navigator.userAgent)&&typeof window.orientation!=="undefined"&&window.orientation !== 0){
                        sWidth = window.screen.height;
                    }else{
                        sWidth = window.screen.width
                    }
                    if(sWidth/deWidth<=1){
                        if (navigator.userAgent.match(/Android (d+.d+)/)){
                            if(parseFloat(navigator.userAgent.match(/Android (d+.d+)/)[1])<4.4||navigator.userAgent.indexOf("MZ-")!==-1){
                                
                                document.documentElement.style.zoom = sWidth/deWidth;
                                return false;
                            }
                        }
                        var meta = document.createElement("meta");
                        meta.setAttribute("name","viewport");
                        meta.setAttribute("content","width=device-width,initial-scale="+(sWidth/deWidth).toFixed(2)+",user-scalable=no,target-densitydpi=device-dpi");
                        
                        document.querySelector("[name=viewport]").remove();
                        document.head.appendChild(meta);
                    }
                },500)
            }
            if(sWidth/deWidth<=1){
                if (navigator.userAgent.match(/Android (d+.d+)/)){
                    
                    if(parseFloat(navigator.userAgent.match(/Android (d+.d+)/)[1])<4.4||navigator.userAgent.indexOf("MZ-")!==-1){
                        document.documentElement.style.zoom = sWidth/deWidth;
                        return false;
                    }
                }
                
                var meta = document.createElement("meta");
                    meta.setAttribute("name","viewport");
                    meta.setAttribute("content","width=device-width,initial-scale="+(sWidth/deWidth).toFixed(2)+",user-scalable=no,target-densitydpi=device-dpi");
                    document.querySelector("[name=viewport]").remove();
                    document.head.appendChild(meta);
            }
        }else{
            document.documentElement.style.zoom = webWidth/deWidth;
        }
    }

    可以在这里看看效果 demo

    2017-07-03 update

    解决window.screen在某些情况下,获取到的并不是可视区的问题,使用document.documentElement.clientWidth代替

    在resize的时候还原zoom或者meta 重新去获取正确的视窗信息(因为缩放的原因,拿到的size是被放大了,之所以不记录缩放系数,因为有可能导致精度问题)

    解决firefox不支持zoom,使用scale兼容

    缩放规则更改
    在安卓设备(4.4以上)上统一使用zoom来缩放(meta,target-densitydpi=device-dpi在某些内核下会自带缩放,即使没有设置initial-scale)

    安卓设备(4.4以下)使用zoom + target-densitydpi=device-dpi

    非安卓的使用<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />来缩放

    var Scale = {
        init:function(deWidth,webWidth){
            var that = this,changeTimer = null;
            that.sWidth = document.documentElement.clientWidth;
            that.deWidth = deWidth;
            that.webWidth = webWidth;
            if(navigator.userAgent.match(/Android (d+.d+)/)&&(parseFloat(navigator.userAgent.match(/Android (d+.d+)/)[1])<4.4)){
                            var meta = document.createElement("meta");
                                meta.setAttribute("name","viewport");
                                meta.setAttribute("content","width=device-width,initial-scale=1,user-scalable=no,target-densitydpi=device-dpi");
                                
                                document.querySelector("[name=viewport]").remove();
                                document.head.appendChild(meta);
            }
            if(navigator.userAgent.indexOf("Mobile")!==-1){
                window.onorientationchange = function(){
                    that.resetScale();
                    changeTimer&&clearTimeout(changeTimer);
                    changeTimer = setTimeout(function(){
                        that.sWidth = document.documentElement.clientWidth;
                        taht.setScale();
                    },500)
                }
                that.setScale();
            }else{
                if(navigator.userAgent.indexOf("Firefox")!==-1){
                    document.documentElement.style.transform = "scale("+that.webWidth/that.deWidth+")";
                }else{
                    document.documentElement.style.zoom = that.webWidth/that.deWidth;
                }
            }
        },
        setScale:function(){
            var that = this;
            if(that.sWidth/that.deWidth<=1){
                if(navigator.userAgent.match(/Android (d+.d+)/)){
                    document.documentElement.style.zoom = that.sWidth/that.deWidth;
                }else{
                    var meta = document.createElement("meta");
                    meta.setAttribute("name","viewport");
                    meta.setAttribute("content","width=device-width,initial-scale="+(that.sWidth/that.deWidth)+",user-scalable=no");
                    document.querySelector("[name=viewport]").remove();
                    document.head.appendChild(meta);
                }
                
                
            }
        },
        resetScale:function(){
            document.documentElement.style.zoom = 1;
            var meta = document.createElement("meta");
            meta.setAttribute("name","viewport");
            meta.setAttribute("content","width=device-width,initial-scale=1,user-scalable=no");
            document.querySelector("[name=viewport]").remove();
            document.head.appendChild(meta);
                        
        }
    }

    结语

    上面只是粗略的代码,可优化的地方还很多,最主要是这种懒适配的思想,当然,因为这种方法使用的较少,应该还存在很多的问题,欢迎指出。

  • 相关阅读:
    linux内核中GNU C和标准C的区别
    linux内核中GNU C和标准C的区别
    Getting start with dbus in systemd (02)
    Getting start with dbus in systemd (01)
    Getting start with dbus in systemd (03)
    物理内存相关的三个数据结构
    数据类型对应字节数(32位,64位 int 占字节数)
    Linux kernel 内存
    共模电感的原理以及使用情况
    [原创]DC-DC输出端加电压会烧毁
  • 原文地址:https://www.cnblogs.com/jesse007/p/7054209.html
Copyright © 2011-2022 走看看