Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web移动端开发总结1--适配篇(2017.10.10) #8

Open
aermin opened this issue Feb 13, 2018 · 2 comments
Open

web移动端开发总结1--适配篇(2017.10.10) #8

aermin opened this issue Feb 13, 2018 · 2 comments

Comments

@aermin
Copy link
Owner

aermin commented Feb 13, 2018

在公司主要写web移动端的项目,一开始较大的感触就是适配很麻烦,分ios和安卓,安卓生态又混乱得很,所以适配要做好了,不然这个设备好好的,有些设备却页面错乱。

在网上找了很多方案,踩了不少坑。

方案一:

(function (doc, win) {
          console.log("dpr:"+win.devicePixelRatio); 
          var docEle = doc.documentElement,
              isIos = navigator.userAgent.match(/iphone|ipod|ipad/gi),
              dpr=Math.min(win.devicePixelRatio, 3);
              scale = 1 / dpr,

              resizeEvent = 'orientationchange' in window ? 'orientationchange' : 'resize';

          docEle.dataset.dpr = dpr;

          var metaEle = doc.createElement('meta');
          metaEle.name = 'viewport';
          metaEle.content = 'initial-scale=' + scale + ',maximum-scale=' + scale;
          docEle.firstElementChild.appendChild(metaEle);
          

          var recalCulate = function () {
                  var width = docEle.clientWidth;
                  if (width / dpr > 640) {
                      width = 640 * dpr;
                   }
                docEle.style.fontSize = 20 * (width / 750) + 'px';
            };

          recalCulate()

          if (!doc.addEventListener) return;
          win.addEventListener(resizeEvent, recalCulate, false);
        })(document, window);

获取设备dpr
算出缩放比例 scale = 1/dpr
创建meta以及属性
将scale值赋给initial-scale,maximum-scale
meta插入到文档中
创建屏幕大小改变重新计算函数并监听

特点:这个方案根据设备等比例缩放,每个设备显示内容一致。
缺点:当我用这套方案时,有个问题,因为监听resizeEvent,导致页面打开会先内容变大,然后再正常显示,很是影响用户体验。
参考链接

方案二(推荐):

    //获取屏幕比例
    function sreenRatio() {
        const ua = navigator.userAgent;
        const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i);
        const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);
        const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;
        const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
        var dpr = window.devicePixelRatio || 1;
        if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {
            // 如果非iOS, 非Android4.3以上, 非UC内核, 就不执行高清, dpr设为1;
            dpr = 1;
        }
        return dpr;
    }
    //初始化屏幕比例
    function screenRatio(baseFontSize, fontscale) {
        var ratio = sreenRatio();     
        var scale = document.createElement('meta');
        var scaleRatio = 1 / ratio;
        scale.name = 'viewport';
        scale.content = 'width=device-width,'+'initial-scale=' + scaleRatio + ', maximum-scale=' + scaleRatio + ', minimum-scale=' +
            scaleRatio + ', user-scalable=no';
        var s = document.getElementsByTagName('title')[0];
        s.parentNode.insertBefore(scale, s);
        var _baseFontSize = baseFontSize || 100;
        var _fontscale = fontscale || 1;
        document.documentElement.style.fontSize = _baseFontSize / 2 * ratio * _fontscale+'px';
    }
        if (window.screen.width >= 768) {
            screenRatio(100, 1.5);//字体放大1.5倍
        } else {
            screenRatio();
        }

特点:

  • 引用简单,布局简便
  • 根据设备屏幕的DPR,自动设置最合适的高清缩放。
  • 保证了不同设备下视觉体验的一致性。(老方案是,屏幕越大元素越大;此方案是,屏幕越大,看的越多)
  • 有效解决移动端真实1px问题(这里的1px 是设备屏幕上的物理像素)
    ps:而且不会出现方案一的问题

缺点:1.有可能会出现字体会不受控制的变大的情况,解决方法:css加上一下内容

*, *:before, *:after { max-height: 100000px }
  1. 感觉没啥问题了,然而我司测试硬生生发现一个bug -> 在某安卓设备发现在QQ上打开网页出现页面错乱。解决方法:判断如果是安卓设备,scale.content加上target-densitydpi=device-dpi

修正:

    //获取屏幕比例
    function getDpr() {
        const ua = navigator.userAgent;
        const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i);
        const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);
        const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;
        const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
        var dpr = window.devicePixelRatio || 1;
        if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {
            // 如果非iOS, 非Android4.3以上, 非UC内核, 就不执行高清, dpr设为1;
            dpr = 1;
        }
        return dpr;
    }
    //初始化屏幕比例
    function screenRatio(baseFontSize, fontscale) {
        var dpr = getDpr();
        var scale = document.createElement('meta');
        var scaleRatio = 1 / dpr;
        scale.name = 'viewport';
		<%/*安卓设备兼容*/%>
		if (/Android/i.test(navigator.userAgent) == true) {
			scale.content = 'width=device-width, target-densitydpi=device-dpi,'+' initial-scale=' + scaleRatio + ', maximum-scale=' + scaleRatio + ', minimum-scale=' +
	            scaleRatio + ', user-scalable=no';
		<%/*iOS设备*/%>
		} else {
			scale.content = 'width=device-width,'+'initial-scale=' + scaleRatio + ', maximum-scale=' + scaleRatio + ', minimum-scale=' +
	            scaleRatio + ', user-scalable=no';
		}
        var s = document.getElementsByTagName('title')[0];
        s.parentNode.insertBefore(scale, s);
        var _baseFontSize = baseFontSize || 100;
        var _fontscale = fontscale || 1;
        document.documentElement.style.fontSize = _baseFontSize / 2 * dpr * _fontscale+'px';
    }
   
   var isAndroid = /Android/i.test(navigator.userAgent) ? true : false;
    <%/*安卓设备不做高清放大处理*/%>
    if (window.screen.width >= 768 && !isAndroid) {
        screenRatio(null, 1.5);<%/*字体放大1.5倍*/%>
    } else {
        screenRatio();
    }

知识点补充:

像素

实际上分为两种:设备像素和CSS像素

1、设备像素(device independent pixels): 设备屏幕的物理像素,任何设备的物理像素的数量都是固定的

2、CSS像素(CSS pixels): 是为web开发者创造的,在CSS和javascript中使用的一个抽象的层,每一个CSS声明和几乎所有的javascript属性都使用CSS像素,因此实际上从来用不上设备像素 ,唯一的例外是screen.width/height

DPR

设备像素比DPR(devicePixelRatio)是默认缩放为100%的情况下,设备像素和CSS像素的比值

DPR = 设备像素 / CSS像素(某一方向上)

以iphone5为例,iphone5的CSS像素为320px568px,DPR是2,所以其设备像素为640px1136px

  • 由于DRP的存在,所以如果不做处理,会有1px线变粗问题,如果DPR为2,那css的1px起始到了设备像素中变了2px的视觉效果。
    解决办法是viewport的initial-scale设置成1/dpr 在页面初始化时缩放成1/2,也就是css的1px变成0.5px,设备像素达到1px的视觉效果(你看到的)。

viewport

一个典型的针对移动端优化的站点包含类似下面的内容:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

width:控制 viewport 的大小,可以指定的一个值,如果 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
height:和 width 相对应,指定高度。
initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
maximum-scale:允许用户缩放到的最大比例。
minimum-scale:允许用户缩放到的最小比例。
user-scalable:用户是否可以手动缩放。

参考链接

@yanlele
Copy link

yanlele commented Mar 14, 2018

推荐使用postcss里面的插件,或者webpack 的px2rem ,会根据屏幕尺寸自动计算换算rem。一站式解决方案。

@aermin
Copy link
Owner Author

aermin commented Mar 14, 2018

@yanlele 感谢推荐😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants