zoukankan      html  css  js  c++  java
  • 国内外移动端web适配屏幕方案总结

    基础知识点

    设备像素设备像素又称物理像素(physical pixel),设备能控制显示的最小单位,我们可以把这些像素看作成显示器上一个个的点。 iPhone5的物理像素是640X1136。

    PS:在普通屏幕下,1个css像素对应1个物理像素(1:1)。

           在超高像素密度屏幕(Retina显示屏)下,1个css像素对应4个物理像素(1:4)。(这里指专指苹果超高清屏幕)

           因此,在移动端方面就需要设置dpr来保证超高清屏显示图片不会失真。

    逻辑像素( logical pixel)独立于设备的用于逻辑上衡量像素的单位。css像素就是逻辑像素,CSS像素是Web编程的概念。iPhone5的逻辑像素是320X568。

    设备独立像素 (density-independent pixel) 简称 dip,单位dp,独立于设备的用于逻辑上衡量像素的单位

    PS:逻辑像素 ≈ 设备独立像素。(设备独立像素是android提出的)

    设备像素比 (device pixel ratio)

    设备像素比 = 设备像素 / 设备独立像素              // 在某一方向上,x方向或者y方向

    iphone5 为例: 640X1136 / 320X568 = 2

    屏幕像素密度(Pibel Per Inch)简称 ppi ,单位是 dpi,一般用来计量电脑显示器,电视机和手持电子设备屏幕的精细程度。通常情况下,每英寸像素值越高,屏幕能显示的图像也越精细。

    屏幕像素密度=屏幕宽度(或高)像素 / 英寸宽屏幕(或高)英寸

    关于设计与开发之间关系

    网页设计师按照设备像素为单位制作设计稿。

    前端工程师按照设备像素比进行换算后的逻辑像素为单位制作网页。

    如:设计图里有元素宽度是100px,那么得到宽度会是 100px/2 = 50px。(仅供参考,以iphone6设计稿的尺寸为例)

    国内方案

    1.固定viewport的宽度等于设备宽度,宽度自适应。

    <meta name="viewport" content="width=device-width,initial-scale=1">  (适合响应式网站)

    PS: 我见很多人都直接固定宽度。如:<meta name="viewport" content="width=640,user-scalable=no">,不建议使用这种固定宽度写法。

             viewport这个属性标签是由Apple公司提出来,其他厂商陆续跟进使用而已。可以说也不是真正标准。

    2.动态生成target-densitydpi值,固定viewport宽度值。

    function adaptVP(a) {
        function c() {
            if(b.uWidth = a.uWidth ? a.uWidth : 640, b.dWidth = a.dWidth ? a.dWidth : window.screen.width || window.screen.availWidth, b.ratio = window.devicePixelRatio ? window.devicePixelRatio : 1, b.userAgent = navigator.userAgent, b.bConsole = a.bConsole ? a.bConsole : !1, a.mode) return b.mode = a.mode, void 0;
            var c = b.userAgent.match(/Android/i);
            if(c) {
                b.mode = "android-2.2";
                var d = b.userAgent.match(/Androids(d+.d+)/i);
                d && (d = parseFloat(d[1])), 2.2 == d || 2.3 == d ? b.mode = "android-2.2" : 4.4 > d ? b.mode = "android-dpi" : d >= 4.4 && (b.mode = b.dWidth > b.uWidth ? "android-dpi" : "android-scale")
            }
        }
    
        function d() {
            var c = "",
                d = !1;
            switch(b.mode) {
                case "apple":
                    c = "width=" + b.uWidth + ", user-scalable=no";
                    break;
                case "android-2.2":
                    a.dWidth || (b.dWidth = 2 == b.ratio ? 720 : 1.5 == b.ratio ? 480 : 1 == b.ratio ? 320 : .75 == b.ratio ? 240 : 480);
                    var e = window.screen.width || window.screen.availWidth;
                    320 == e ? b.dWidth = b.ratio * e : 640 > e && (b.dWidth = e), b.mode = "android-dpi", d = !0;
                case "android-dpi":
                    var f = 160 * b.uWidth / b.dWidth * b.ratio;
                    c = "target-densitydpi=" + f + ", width=" + b.uWidth + ", user-scalable=no", d && (b.mode = "android-2.2");
                    break;
                case "android-scale":
                    c = "width=" + b.uWidth + ", user-scalable=no"
            }
            var g = document.querySelector("meta[name='viewport']") || document.createElement("meta");
            g.name = "viewport", g.content = c;
            var h = document.getElementsByTagName("head");
            h.length > 0 && h[0].appendChild(g)
        }
    
        function e() {
            var a = "";
            for(key in b) a += key + ": " + b[key] + "; ";
            alert(a)
        }
        if(a) {
            var b = {
                uWidth: 0,
                dWidth: 0,
                ratio: 1,
                mode: "apple",
                userAgent: null,
                bConsole: !1
            };
            c(), d(), b.bConsole && e()
        }
    }

    PS:实在不知道是源代码是怎么来的,是从项目中抽取出来的。这种方案已经不推荐使用

          

    3.动态initial-scale,maximum-scale,minimum-scale值,固定viewport宽度值。

    /**
     * MobileWeb 通用功能助手,包含常用的 UA 判断、页面适配、search 参数转 键值对。
     * 该 JS 应在 head 中尽可能早的引入,减少重绘。
     *
     * fixScreen 方法根据两种情况适配,该方法自动执行。
     *      1. 定宽: 对应 meta 标签写法 -- <meta name="viewport" content="width=750">
     *          该方法会提取 width 值,主动添加 scale 相关属性值。
     *          注意: 如果 meta 标签中指定了 initial-scale, 该方法将不做处理(即不执行)。
     *      2. REM: 不用写 meta 标签,该方法根据 dpr 自动生成,并在 html 标签中加上 data-dpr 和 font-size 两个属性值。
     *          该方法约束:IOS 系统最大 dpr = 3,其它系统 dpr = 1,页面每 dpr 最大宽度(即页面宽度/dpr) = 750,REM 换算比值为 16。
     *          对应 css 开发,任何弹性尺寸均使用 rem 单位,rem 默认宽度为 视觉稿宽度 / 16;
     *              scss 中 $ppr(pixel per rem) 变量写法 -- $ppr: 750px/16/1rem;
     *                      元素尺寸写法 -- html { font-size: $ppr*1rem; } body {  750px/$ppr; }。
    
     */
    window.mobileUtil = (function(win, doc) {
        var UA = navigator.userAgent,
            isAndroid = /android|adr/gi.test(UA),
            isIos = /iphone|ipod|ipad/gi.test(UA) && !isAndroid, // 据说某些国产机的UA会同时包含 android iphone 字符
            isMobile = isAndroid || isIos;  // 粗略的判断
    
        return {
            isAndroid: isAndroid,
            isIos: isIos,
            isMobile: isMobile,
    
            isNewsApp: /NewsApp/[d.]+/gi.test(UA),
            isWeixin: /MicroMessenger/gi.test(UA),
            isQQ: /QQ/d/gi.test(UA),
            isYixin: /YiXin/gi.test(UA),
            isWeibo: /Weibo/gi.test(UA),
            isTXWeibo: /T(?:X|encent)MicroBlog/gi.test(UA),
    
            tapEvent: isMobile ? 'tap' : 'click',
    
            /**
             * 缩放页面
             */
            fixScreen: function() {
                var metaEl = doc.querySelector('meta[name="viewport"]'),
                    metaCtt = metaEl ? metaEl.content : '',
                    matchScale = metaCtt.match(/initial-scale=([d.]+)/),
                    matchWidth = metaCtt.match(/width=([^,s]+)/);
    
                if ( !metaEl ) { // REM
                    var docEl = doc.documentElement,
                        maxwidth = docEl.dataset.mw || 750, // 每 dpr 最大页面宽度
                        dpr = isIos ? Math.min(win.devicePixelRatio, 3) : 1,
                        scale = 1 / dpr,
                        tid;
    
                    docEl.removeAttribute('data-mw');
                    docEl.dataset.dpr = dpr;
                    metaEl = doc.createElement('meta');
                    metaEl.name = 'viewport';
                    metaEl.content = fillScale(scale);
                    docEl.firstElementChild.appendChild(metaEl);
    
                    var refreshRem = function() {
                        var width = docEl.getBoundingClientRect().width;
                        if (width / dpr > maxwidth) {
                            width = maxwidth * dpr;
                        }
                        var rem = width / 16;
                        docEl.style.fontSize = rem + 'px';
                    };
    
                    win.addEventListener('resize', function() {
                        clearTimeout(tid);
                        tid = setTimeout(refreshRem, 300);
                    }, false);
                    win.addEventListener('pageshow', function(e) {
                        if (e.persisted) {
                            clearTimeout(tid);
                            tid = setTimeout(refreshRem, 300);
                        }
                    }, false);
    
                    refreshRem();
                } else if ( isMobile && !matchScale && ( matchWidth && matchWidth[1] != 'device-width' ) ) { // 定宽
                    var    width = parseInt(matchWidth[1]),
                        iw = win.innerWidth || width,
                        ow = win.outerWidth || iw,
                        sw = win.screen.width || iw,
                        saw = win.screen.availWidth || iw,
                        ih = win.innerHeight || width,
                        oh = win.outerHeight || ih,
                        ish = win.screen.height || ih,
                        sah = win.screen.availHeight || ih,
                        w = Math.min(iw,ow,sw,saw,ih,oh,ish,sah),
                        scale = w / width;
    
                    if ( scale < 1 ) {
                        metaEl.content = metaCtt + ',' + fillScale(scale);
                    }
                }
    
                function fillScale(scale) {
                    return 'initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale + ',user-scalable=no';
                }
            },
    
            /**
             * 转href参数成键值对
             * @param href {string} 指定的href,默认为当前页href
             * @returns {object} 键值对
             */
            getSearch: function(href) {
                href = href || win.location.search;
                var data = {},reg = new RegExp( "([^?=&]+)(=([^&]*))?", "g" );
                href && href.replace(reg,function( $0, $1, $2, $3 ){
                    data[ $1 ] = $3;
                });
                return data;
            }
        };
    })(window, document);
    
    // 默认直接适配页面
    mobileUtil.fixScreen();

    PS:这方案与方案2雷同(不是完美的解决方案)

             缺点:比如说页面里面有个二维码,android可以识别到,iphone却不可以识别。

    4.动态生成initial-scale,maximum-scale,minimum值,布局宽高使用rem,然后html标签设置font-size,利用fone-size来控制rem宽高,并且还设备像素比来设置dpr来适配不同移动设备的屏幕密度显示。

    手淘方案:lib-flexible (过时了)

    墨尘方案:hotcss

    PS:补充一种简单适配方案,这种方法相对简单,与手淘方案类似,但无需js引入。

            首先居中布局,定宽。

            以iphone6为基准,设计稿是750px。

            设计稿宽度/100 = 7.5  把1rem=100px转换,比值是7.5。

            也就是  设计稿宽度与rem的比值是7.5。        

            320px /7.5 = 42.6666(html的font-size值)   

            写出不同设备媒体查询font-size值。

    @media only screen and (min- 320px) {
        html {
            font-size: 42.6666px
        }
    }
    
    ...

             设计稿元素高宽/100 就得出元素的高宽rem。

    div {
        height: 100px;
        width: 100px;
    }
    
    /*转rem*/
    
    div {
        height: 1rem;
        width: 1rem;
    }

    5.利用新的css属性 @viewport 进行适配。

    @viewport {
        width: device-width; /*设置宽度为设备宽度*/
        min-width: 640px;
        max-width: 800px;
    }
    @viewport {
        user-zoom:fixed; /*zoom 允许用户缩放,fixed 不允许用户缩放*/
        zoom: 0.75;
        min-zoom: 0.5;
        max-zoom: 0.9;
    }
    @viewport {
        orientation: landscape; /*landscape 页面横屏显示,landscape 页面竖屏显示。*/
    }

    PS:这个属性可以配合@media规则使用,完美适配各种复杂设备屏幕。强烈推荐使用。

              等价于<meta name="viewport" content="width=device-width,initial-scale=1">。

              需要加浏览器厂商前缀。

    补充:使用css media queries不要使用rem单位。(Safari浏览器存在不兼容问题)

               使用rem或者em单位的性能略低于px。(原因是px是绝对单位,rem与em是相对单位)

               使用rem与em单位效果是差不多,唯一的区别是rem是根据html标签的字体大小,em是根据相对当前元素(或者是父元素)的字体大小。

               

    rem             

    html {
        font-size:16px;
    }
    
    div {
        width: 10rem;   //16px*10 = 160px;
        height: 10rem;  //16px*10 = 160px;
    } 

    em 

    //当前元素
    
    .header {
          font-size: 16px;
          width: 100%;
          height: 10em; //16px*10=160px;
    }
    
    //父元素
    
    .header {
          font-size: 18px;
    }
    
    .header div{
          width: 100%;
          height: 10em; //18px*10=180px;
    }

    国外方案

    Google(Facebook,亚马逊,YouTube,eBay和雅虎)适配方案做法

    原理: google PC端 与 google 移动端是分开的,PC端与移动端页面是响应的。(是响应式移动网站与响应式PC网站)

              依赖用户代理字符串,通过同一网址向特定用户代理下查看时展示不同内容的技术。

              依旧采用px单位+媒体查询进行适配。      

    比较:国内方案优点:精准,通过js计算,再配合css进行适配屏幕。

                               缺点:需要依赖,客户端压力大(需要js配合)。

              google方案优点:简单,通过服务器端去判断,配合css媒体查询进行适配屏幕,效率高,无依赖。

                               缺点:不精准。服务端压力大。

    总结:获取UA并不能获取用户的浏览器信息,因为很多移动浏览器可以设置自定义UA。

               具体问题具体分析。(优先考虑性能)

  • 相关阅读:
    Android开发 ViewConfiguration View的配置信息类
    Android 开发 倒计时功能 转载
    Android 开发 关于7.0 FileUriExposedException异常 详解
    Android 开发 实现文本搜索功能
    Android 开发 Activity里获取View的宽度和高度 转载
    Android 开发 存储目录的详解
    Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView
    Android 开发 将window变暗
    Android 开发 DisplayMetrics获取Android设备的屏幕高宽与其他信息
    Android 开发 DP、PX、SP转换详解
  • 原文地址:https://www.cnblogs.com/Sroot/p/5922937.html
Copyright © 2011-2022 走看看