移动端适配方案

1,559 阅读6分钟

media queries

运用css来判断设备宽度在不同的区间运用不同的样式 :

p{
	font-size:18px;
}

@media screen and (max-width: 1200px) and (min-width: 769px){
	p{
		font-size:16px;
	}
}

@media only screen and (max-width: 768px){
	p{
		font-size:14px;
	}
}

优点:无需插件,能够适应各种窗口大小,只需在CSS中添加@media screen属性。

缺点:相对于代码要重复很多 ; 可能存在闪屏的问题出现。

rem

rem是指相对于根元素的字体大小的单位,就是先给予html元素一个font-size,然后我们所有的rem就根据这个font-size来计算(本质是布局等比例的缩放)。

html{
	font-size:16px;
}
p{
	font-size:2rem;//即为font-size:32px;
}

原理是先按定高宽设计出来页面,然后转换为rem单位,配合js查询屏幕大小来改变html的font-size。

js运算

基于JS进行屏幕分辨率计算(以750为例):

document.documentElement.style.fontSize = document.documentElement.clientWidth / 750 + 'px';

Sass与rem

  1. @function

    根据rem的使用原理,可以知道pxrem需要在html根元素设置一个font-size值,因为rem是相对于html根元素。在Sass中定义一个pxrem的函数,先要设置一个默认变量:

    $base-font-size: 16px !default;//变量的值可以根据自己需求定义
    

    而且需要在html根元素中显示的声明 font-size:

    html { font-size: $base-font-size; }
    

    然后通过@function来实现px转为rem计算($px为需要转换的字号):

    @function pxTorem($px){
    	$base-font-size * 1rem; 
    }
    

    定义好@function之后,实际使用中就简单多了:

    //sass
    html { 
    	font-size: $base-font-size; 
    } 
    .header { 
    	font-size: pxTorem(12px); 
    }
    
    //css
    html{
    	font-size:16px;
    }
    .header{
    	font-size:0.75rem;
    }
    

    不过@function不能同时服务于多个属性值的计算,如:

    .header { 
    	font-size: pxTorem(12px); 
    	margin: pxTorem(5px 10px);//同时计算多个值将报错 
    }
    

    换句话说,这个函数仅适合运用在具有单个属性值的属性上,例如 font-size,如果要强制使用,只能使用多个pxTorem():

    .header { 
    	font-size: pxTorem(12px); 
    	margin: pxTorem(5px) pxTorem(10px);
    }
    
  2. @mixin

    @mixin font-size($target){ 
        font-size: $target;
    	font-size: ($target / $base-font-size) * 1rem; 
    }
    

    在实际使用中,可以通过@include调用定义好的@mixin font-size:

    //SCSS 
    .footer { 
    	@include font-size(12px); 
    } 
    
    //CSS 
    .footer { 
    	font-size: 12px; font-size: 0.75rem; 
    }
    

    可实际中,我们很多样式属性中不只一个属性,为了实现多个属性能设置多值,就需要对mixin做出功能扩展(理解代码块):

    @mixin remCalc($property, $values...) { 
        $max: length($values);//返回$values列表的长度值 
        $pxValues: ''; 
    	$remValues: ''; 
    	@for $i from 1 through $max { 
            $value: strip-units(nth($values, $i));//返回$values列表中的第$i个值,并将单位值去掉 
            $browser-default-font-size: strip-units($browser-default-font-size); 
            $pxValues: #{$pxValues + $value * $browser-default-font-size}px; 
            @if $i < $max { 
            $pxValues: #{$pxValues + " "}; 
            } 
    	} 
    	@for $i from 1 through $max { 
            $value: strip-units(nth($values, $i));
            $remValues: #{$remValues + $value}rem; 
            @if $i < $max { $remValues: #{$remValues + " "};
            }
        }
        #{$property}: $pxValues; 
        #{$property}: $remValues; 
    }
    

    pxremmixin定义完成后,就可以通过@include来引用:

    //SCSS 
    .wrapper { 
        @include remCalc(width,45); 
    	@include remCalc(margin,1,.5,2,3);
    } 
    //CSS 
    .wrapper { 
        width: 720px; width: 45rem; 
        margin: 16px 8px 32px 48px; 
    	margin: 1rem 0.5rem 2rem 3rem; 
    }
    

    在实际使用中取值有一点非常重要,在remCalc()取的$values值为rem值。

  3. 实际应用

    那么如何把UI图中的获取的像素单位的值,转换为以rem为单位的值呢?公式是元素宽度 / UE图宽度 * 100。例如,UI图尺寸是640px,UI图中的某元素宽度是100px,根据公式100/640*100 = 15.625:

    p{
    	width:15.625rem;
    }
    

    以上可以用Sass,预处理的function来简化过程:

    $ue-width: 640; 
     
    @function pxTorem($px) {
      @return #{$px/$ue-width * 100}rem;
    }
     
    p {
      width: pxTorem(100);
    }
    

    上面的代码编译完的结果如下:

    p {
    	width: 15.625rem;
    }
    

优缺点

优点:能维持能整体的布局效果,移动端兼容性好,不用写多个css代码。

缺点:

不是纯css移动适配方案,需要引入js脚本 在头部内嵌一段 js脚本 监听分辨率的变化来动态改变根元素的字体大小;

css样式和 js 代码有一定 耦合性,并且必须将改变font-size的代码放在 css 样式之前;

html的font-size设置到12px以下还是会按照12px=1rem来计算,这样所有使用了rem单位的尺寸都是错的。

vw

视口单位, 1vw 等于视口宽度的1%, 假如浏览器的宽度为200px,那么1vw就等于2px(200px/100)。

  • vw : 1vw 等于视口宽度的1%
  • vh : 1vh 等于视口高度的1%
  • vmin : 选取 vw 和 vh 中最小的那个
  • vmax : 选取 vw 和 vh 中最大的那个

单位换算

如果要将px换算成vw,只要确定视图的窗口大小(布局视口)。如果我们将布局视口设置成分辨率大小,比如对于iphone6/7 375*667的分辨率,那么px可以通过如下方式换算成vw:

1px = (1/375)*100 vw;

简单来说,如果UI设计稿为750px,那么100vw=750px,即1vw=7.5px;

此外,也可以通过postcss的相应插件,预处理css做一个自动的转换,postcss-px-to-viewport可以自动将px转化成vw。 postcss-px-to-viewport的默认参数为:

var defaults = {
  viewportWidth: 320,
  viewportHeight: 568, 
  unitPrecision: 5,
  viewportUnit: 'vw',
  selectorBlackList: [],
  minPixelValue: 1,
  mediaQuery: false
};

优缺点

优点:纯css移动适配方案,不需要引入js脚本

缺点:兼容性差,安卓4.4以下都不支持

rem+vw

通过采用rem单位的动态计算的弹性布局,则是需要在头部内嵌一段脚本来进行监听分辨率的变化来动态改变根元素字体大小,使得CSS于JS耦合了在一起,而只使用vw,其兼容性问题又阻隔着。而将二者结合起来,通过利用适口单位实现适配的页面,是既能解决脚本依赖的问题,又能解决兼容性问题。

用法(iPhone6为基准(750))

  1. 对移动端进行meta标签设置(因为iPhone6以及大多数的dpr为2,为了第二步的方便进行换算)

    <meta name="viewport" content="width=device-width, initial-scale=2.0, maximum-scale=2.0, minimum-scale=2.0, user-scalable=no">
    
  2. 设置body、html的font-size

    html {
        font-size: 13.3333333333333vw // 设计图100px,浏览器根据缩放为 50px;
    }
    

    13.3333333333333vw怎么来? 100 / 750 = 0.133333333333333vw

    我们把这个适口当做100px,然后除于750换算得出 1px = 0.133333333333333vw

    那么整个适口等于 0.133333333333333 * 100 = 13.3333333333333vw = 100px,最终于得出 100px = 1rem

    通过这样子换算我们利用vw把rem转换成了根据设计以100px为基准

    然后我们即可根据设计稿(前提设计稿是750px的),这样我们写1rem即为设计稿上的100px

    1. 设计稿的单位是px,一般是750px。

    2. px、rem混合着用,rem的html font-size用16px。

    3. 750px的设计图以375px量长宽,例如设计图里有元素宽度是100px,那么得到宽度会是 100px/2/16px = 3.125rem。

场景1:

设计稿是750px,某按钮是100px,其width=50px(100/20=50)

默认下,1rem = 16px,所以100px = 100 / dpr / 16 = 50/16=3.125rem,按钮的宽度则为3.125rem

1rem=100px,所以100px=100/2/100=0.5rem,(缩放为50px),因此为1rem 场景2: 设计稿某图片是250px

100px =1rem,(缩放为50px)

所以是2.5rem,应该设为2.5rem

所以因为2.5rem*2=5rem

~~有什么问题多指教~都是我自己理解来的嘻嘻嘻~