• 你必须要知道的移动端开发知识


    摘自:https://www.cnblogs.com/wonyun/p/11932142.html

    你必须要知道的移动端开发知识

     

    移动开发不同与PC端开发,可能会经历各种意想不到的问题,尤其是移动端应用刚起步的几年;随着移动互联网的快速发展,有些问题已经得到了很好的支持,如1像素边界的问题。当然,要更好地解决这些移动端的问题,就需有移动端领域相关的知识,下面就来说说。

    dpr设备像素比

    首先说一下,这个dpr不仅仅是移动端才有的,pc端也有,但是对一些移动端的问题产生的原因及解决显得比较重要,比如1像素的问题。先来看几个概念:

    1. 物理像素(physical pixel)

      一个物理像素就是显示设备上最小的物理显示单元,每个物理像素都有自己的颜色值和亮度值。例如iphone6手机屏幕有750*1334个物理像素

    2. 设备独立像素(density-independent

      设备独立像素又叫密度无关像素,也可以叫逻辑像素,程序使用的虚拟像素如css像素,可以理解为显示设备坐标系统中的一个点;

    3. 设备像素比dpr(device pixel ratio)

      设备像素比,简称dpr,定义了物理像素与设备独立像素之间的对应关系,具体的对应关系是一个计算公式如下:

      dpr = 物理像素 / 设备独立像素

      上面计算的dpr是指某一个方向上如x或者y方向,二者dpr值相同;程序中获取dpr方式如下:

      • js获取dpr使用window.devicePixelRatio

      • css获取dpr使用-webkit-device-pixel-radio

      例如iphone6,设备宽高375 * 667,可以理解为设备独立像素(也即css像素);其dpr为2,那么对应的物理像素宽高均 * 2,即 750 * 1334;也就是说一个逻辑像素,在x轴和y轴都需要2个物理像素来显示,一图胜千言,如图:

      由上线描述可以知道,css中的1px并不等于显示设备的物理1px,这就导致移动开发中设计师设计的是1px的物理像素,而转换为css的值为1/dpr,其可能为小数值,这在低版本android(<=4.4)和ios(<=8)中被会系统自动转换为0,这就是移动端常见的1px像素的问题;下面会给出具体的解决方案。

    viewport

    做过移动端开发的同学可能对下面html中的meta标签比较熟悉:

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" >

    这个是用来控制移动端viewport区域是怎么展现的,很有必要对其理解。

    viewport理解

    在PC的浏览器中,viewport其实就是浏览器可视区域,但是在移动设备上问题就比较复杂,viewport并不局限于浏览器可视区域大小,可能比浏览器可视区域要大,也可能比浏览器可视区域要小;但是因为移动端屏幕相较pc端太窄,为在移动端正常显示为PC端设计的网站,默认情况下移动端设备上的viewport都是要大于浏览器可视区域的,一般值为980px也可能有其他值,根据不同设备来定;因为viewport比浏览器可视区域大,那么浏览器就会出现横向滚动条。

    需要注意两点:

    1. 页面的html标签的宽度就是相对于viewport的大小。

    2. PC端viewport就是浏览器可视区域大小;移动端默认viewport值为980px,也可以根据meta标签自定义设置。

    有关viewport理论,国外有一个人ppk对此有做过比较深入的研究,具体可以参考其写的三篇文章 。其将viewport分成三个层面来理解:

    • layout viewport

      布局窗口,网页真正的布局视口,它的宽度可以大于也可以小于浏览器可视区域的宽度,对于大于浏览器可视区域(比如默认980px的viewport或者自定义设置viewport)的viewport,只能通过滚动浏览器滚动条来展现其内容。

    • visual viewport

      可视窗口,移动设备浏览器可视区域的大小,其宽度并一定为移动显示设备的屏幕宽度,在initial-scale缩放为1的情况下才相等。

    • ideal viewport

      理想化的窗口,它没有一个固定的尺寸,其宽度为移动设备屏幕宽度,它是最适合移动设备的viewport。设置理想化的窗口的网页不论何种分辨率的屏幕下,其用户不需要缩放和横向滚动条就能正常查看网站所有内容,保证网页的文字、图片等等其大小完美的呈现给用户。

    一图胜千言,借用网上的几张图来说明具体的区别:

    上面两幅图很好理解,下面两幅对比图,说明ideal viewport对于网站用户体验的重要性,用户不用缩放或者滚动就能达到极佳的体验效果。

    用meta标签控制viewport

    <meta name="viewport" content="xxx"> 标签来控制viewport大小首先是由苹果公司在其safari浏览器中引入的,目的就是解决移动设备的viewport问题。后来安卓以及各大浏览器厂商也都纷纷效仿,引入它对viewport的支持。

    viewport是通过meta标签来控制页面的viewport大小,具体形式如下:

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" >

    其中width=device-width顾名思义是设置viewport的宽为设备的宽,其还可以设置具体的逻辑像素值,如980。

    meta标签的viewport相关配置content值有6个属性,它们可以同时使用,也可单独使用,还可以混合使用,具体如下:

    width设置layout viewport的宽度,为一正整数,也可为device-width
    height 设置layout viewport的宽度,为一正整数,很少使用
    initial-scale 设置页面的初始缩放值,为一数值,可带小数
    minimum-scale 设置页面的最小缩放值,为一数值,可带小数
    maximum-scale 设置页面的最大缩放值,为一数值,可带小数
    user-scalable 页面是否允许缩放,值为"no"或"yes", no 不允许,yes允许

    需要注意两点:

    1. user-scalable=no禁止缩放在ios>=10系统的safari下有兼容问题,具体可以看禁止页面缩放meta标签兼容性问题这部分

    2. meta属性中initial-scale的缩放是相对于ideal viewport来进行的

    这样通过meta标签很容易设置页面layout viewport为移动设备屏幕宽度(它也是ideal layout)即:

    <meta name="viewport" content="width=device-width">

    上面这种方式是最直接也是最轻易想到的设法,但是还可以使用initial-scale来达到同样的效果,即:

    <meta name="viewport" content="initial-scale=1">

    简单解释下,initial-scale表示页面初始缩放值,其缩放是相对于ideal viewport的来说的,为1表示不缩放,那么其layout viewport的宽度就是ideal viewport的宽度,也就是移动设备屏幕的宽度。

    既然二者都可以设置layout viewport的宽度,那么二者同时设置且值不相等会怎样呢?答案是:

    浏览器会以二者中值较大的那个为准

    可能读者会有新的疑惑,在设置layout viewport为屏幕宽度时,经常看到的是二者都写上,为什么呢?答案是:

    一个是兼容性的考虑,另一方面解决某些设备横竖屏不分导致通通以ideal viewport的宽度为准的问题

    viewport的缩放

    上面提到,meta中的initial-scale是相对于ideal viewport进行缩放的,该属性的作用:

    initial-scale用来确定visual viewport即浏览器可视区域宽度大小

    阿里早期的iphone/ipad下的自适应布局解决方案flexible就是利用initial-scale来解决的。

    有人可能会有疑问,移动端浏览器可视区域宽度不就是移动设备屏幕的宽度么?其实我们这里所说的可视区域宽度是逻辑意义上的宽度,而非实际真实的宽度,例如iphone4的320px屏幕宽度,initial-scale放大2倍,那么可视区域的逻辑大小变成了160px,可以通过查看页面html元素的宽度测试。

    其实visual viewport与ideal viewport的关系如下:

    visual viewport = ideal viewport / initial-scale

    在iphone/ipad下,在没有指定initial-scale的情况下,无论你怎么设置layout viewport宽度,它会根据上面的计算关系,自动计算当前页面的inital-scale值以保证layout viewport宽度在缩放后就是浏览器可视区域的的宽度,即inital-scale = ideal viewport宽度 / visual viewport宽度(等于layout viewport宽度)

    例如,iphone6情况下默认的layout viewport为980px,那么当前缩放值inital-scale=375 / 980。

    需要说明一下的是:在设置了initial-scale的情况下,这个自动计算的值就不起作用了。

    移动适配方案

    移动端设备不同,其屏幕大小也不尽相同,那么针对特定移动设备的页面设计ui怎么在不同移动设备上因设备不同而自适应屏幕展示呢。一般常见的解决方案有rem和vw/vh。下面就来说说。

    rem适配

    rem是一个相对单位,相对于<html>font-size来说的;那么参与页面布局的单位使用rem而不是px,这样我们只需控制不同设备下网页<html>font-size即可做到页面的自适应。

    可以像flexible一样将移动屏幕宽度100等份,每份为a,同时1rem认定为10a;例如750px的设计稿来说,这样的话:

    1a = 750px / 100 = 7.5px
    1rem = 10a = 75px

    实现代码如下:

    (function (doc, win) {
    var docEl =doc.documentElement,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
        recalc = function () {
          var width = docEl.getBoundingClientRect().width;
          if (!width) return;
          docEl.style.fontSize = (width / 100)*10 + 'px';
        };
    
      if (!doc.addEventListener) return;
      win.addEventListener(resizeEvt, recalc, false);
      recalc();
      // hack兼容某些特殊机型
      doc.addEventListener('DOMContentLoaded', recalc, false);
    })(document, window);

    另外,我们也可以基于特定的设计稿尺寸来计算其他移动设备下的font-size,例如基于750px的设计稿,我们假设其font-size为40px,那么其他设备下font-size的计算关系式:

    750/40=/fontsize750/40=设备屏幕宽/fontsize

    对应的核心转换代码即: docEl.style.fontSize = (width / 750)*40 + 'px'

    VW适配

    首先要知道vw和vh的概念代表什么,它也是相对单位,相对于屏幕的宽高而言的。

    100vw = ideal viewport 宽
    
    100vh = ideal viewport 高

    跟rem类似,我们可以使用vw单位作为css的唯一单位,这样所有元素基于vw来布局;基于特定设计稿的尺寸来转换vw单位,我们使用stylus预编译函数来进行转换:

    $vw_base = 375
    vw(px) {
       (px/$vw_base) * 100vw
    }

    然后无论是文本还是布局高宽、间距等都使用 vw 作为 CSS 单位,如

    .container
      padding: vw(15) vw(10) vw(10)
      height: vw(40)

    vw+rem结合适配

    单纯的vw适配在视口缩放时尤其是缩小时有些小瑕疵,因为vw是利用视口单位实现的布局,依赖视口的大小而自动缩放,也就失去了最大最小的宽度限制。一种比较好的解决方法是使用vw与rem配合来进行适配,即:

    页面需要适配的元素使用rem为单位,而的font-size值是根据vw来设定的,但是该font-size值需要限制最大最小值。

    具体的stylus代码如下,也可以参考这个demo猛戳

    $fontsize = 75 // 将屏幕分成10份
    $base = 750 // iphone6 750作为基数
    rem(px) {
        (px/$fontsize) * 1rem
    }
    
    html 
      font-size: ($fontsize / $base) * 100vw //font-size以vw为单位
      // 通过medai query限制根元素的最大值最小值
      @media screen and (max- 320px) {// 页面宽度<=320时生效
          font-size: 64px
      }
      @medai screen and (min- 540px) { // 页面宽度>=540时生效
          font-size: 108px
      }

    媒体查询media query适配

    通过类似如下形式来实现适配:

    /* 大于1200px */
    @media screen and (min-1200px){}
    /* 大于等于960px,小于1200px */
    @media screen and (min- 960px) and (max- 1199px){}
    /* 大于等于768px,小于960px */
    @media screen and (min- 768px) and (max- 959px){}
    /* 大于等于480px,小于768px */
    @media only screen and (min- 480px) and (max- 767px){}
    /* 小于479px */
    @media only screen and (max- 479px){}

    该方式比较简单,成本低,但是代码量大,比较臃肿,维护不方便,不推荐该方式。

    阿里flexible适配

    该方案随着viewport单位 得到众多浏览器的兼容支持已逐渐不推荐使用了,它主要是为了解决iphone系列适配问题;虽然官方已不推荐使用,但是其思想还是值得借鉴学习的,主要表现下面三个方面:

    • 根据dpr的值来修改<meta>viewport的值实现移动端1px的问题

    • 根据dpr的值来修改<html>font-size值,使用以rem为单位值来等比例缩放

    • 使用hack手段用rem模拟vw特性

    对应第一点,它通过hack手段来根据设备的dpr值相应改变<meta>标签中的viewport的值:

    <!-- dpr = 1-->
    <meta name="viewport" content="initial-scale=scale,maximum-scale=scale,minimum-scale=scale,user-scalable=no">
     <!-- dpr = 2-->
    <meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">
     <!-- dpr = 3-->
    <meta name="viewport" content="initial-scale=0.3333333333,maximum-scale=0.3333333333,minimum-scale=0.3333333333,user-scalable=no">

    这样,iphone系统的不同设备下页面达到的效果是使css 1px像素与物理1px像素相同;然后,flexible使用rem作为布局单位实现适应布局。关键基本代码如下:

    // 设置meta的viewport内容进行缩放
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
        // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
        if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                
            dpr = 3;
        } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
            dpr = 2;
        } else {
            dpr = 1;
        }
    } else {
        // 其他设备下,仍旧使用1倍的方案
        dpr = 1;
    }
    scale = 1 / dpr;
    
    // 确定html的font-size值
    var width = docEl.getBoundingClientRect().width;
    if (width / dpr > 540) {
        width = 540 * dpr;
    }
    var rem = width / 10; // 屏幕均分100份,每份为a,1rem为10a
    docEl.style.fontSize = rem + 'px';

    1px边框问题及解决方案

    产生1px边框的问题其实归结三点:

    • 1px的css逻辑像素不等于1px的物理像素

    • ios<8以及Android<=4.4以下的浏览器处理0.5px时会转化为0

    对于1px边框问题的解决,flexible能完美的解决,思路见上面分析的;除此之外还有什么方式,其实网上有很多方法,但是还是列一下思路:

    1. 用border-image来实现

      有关border-image的请猛戳border-image 的正确用法;需要使用一张图片来充当border,图片大小是6px X 6px,如下:

      .border {
          border- 1px;
          border-image: url(border.png) 2 repeat; /*用border-image-slice设置图片的四条切割线为2图片像素*/
      }

      缺点:改边框颜色时要修改图片,不灵活

    2. 用背景渐变来实现

      设置1px的渐变背景,50%有颜色,50%透明

      .border {
          background-image: linear-gradient(180deg, green, green 50%, transparent 0);
        background-size: 100% 1px; /* 背景宽度100%,高度1px */
        background-repeat: no-repeat;
        background-position: bottom;
      }

      缺点:维护过多代码,圆角没法实现

    3. 用box-shadow模拟边框来实现

      .border {
          border: none;
          height: 100px;
           100%;
          box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.5);
      }

      缺点:颜色不好处理,有阴影出现

    4. 用伪类+transform来实现

      比较推荐的方法,原理是把原先元素的border去掉,然后利用:before或者:after重做border,并把transformscale缩小一半,原先元素相对定位,伪元素模拟的border采用绝对定位。

      .border {
          position: relative;
          border: none;
      }
      .border:after {
          content: ' ';
          position: absolute;
          left: 0;
          background: #666;
           100%;
          height: 1px;
          tranform: scaleY(0.5);
          transform-origin: 0 0;
      }

    参考文献

     
    分类: html/css
  • 相关阅读:
    Python全栈day10(基础知识练习题)
    Python全栈day10(基本数据类型及其常用方法)
    Python全栈day10(运算符)
    CentOS 添加常用 yum 源(转)
    CentOS yum源设定使用方法的整理(转)
    centos6.6安装php5.3.3(2015/3/4)
    centos6.6升级安装MySQL5.5(2015/3/4)
    vi/vim显示中文字符并且去掉^M的方法
    ecmall2.3.0 前后台样式等无效,导致前台页面显示不正常问题解决
    ecmall页面空白解决方案(转)
  • 原文地址:https://www.cnblogs.com/xichji/p/11981525.html
Copyright © 2020-2023  润新知