强大大

导航

移动端屏幕适配原理以及方法讲解

序言:

今天周日,我正坐在黄埔区图书馆,思索着关于移动端屏幕适配的问题。作为一名年纪轻轻的前端马蓉,不,是码农,移动端屏幕适配的方案的帖子没读过100篇吧,也读过几十篇了。可是今天我又在思考这个问题了,因为下周我有个关于移动端适配的演讲。人生这么短暂,我却把有限的时间奉献到了无限的前端道路上。

根据我不(cong)太(ming)灵(jue)活(ding)的大脑的努力思考。我发现现阶段比较流行移动端适配原理只有一个——就是对元素进行放大和缩小,具体到执行的时候方法有两个(求不打脸)。 1个是网页大小不变只对其中的元素进行放大缩小的rem单位值缩放法,另1种是对直接对整个网页进行放大缩小的网页缩放法。为什么你没有听过这两个方法?因为这两个方法的名字都是我起的,还没著名起来。

  1. rem单位值缩放法;具体做法是让1rem对应的px值根据手机的不同而不同,可能在iphne5上1rem等于10px,在iphone6上1rem就等于11.7px了(iphone6的屏幕宽度是iPhone5屏幕宽度的1.17倍,所以1rem对应的px值也要是1.17倍)。 具体1rem值是多少,可以通过js或者css3的媒体查询算出来。然后网页上的元素都使用rem作为尺寸单位。iphone5上表现良好的页面,放到iphone6上的时候,因为rem对应的px值被放大了,所以所有元素的尺寸位置也被等比例放大了,所以在iphone6下自然也就表现良好了。修改rem值的方法有两个。

    1.1 使用js修改html的fontsize值大小。

    1.2 使用媒体查询修改html的fontsize值大小。

  2. 网页缩放法:这个方法就简单暴力了,搞得人心里经常怕怕的。具体做法就是以一个手机为基准,一般是iphone5。在iphone5上先制作好页面,制作完页面之后再在页面加入一段适配的js,这段js的作用就是获取屏幕的宽度然后与iphone5进行比较,比iphone5宽的就把网页放大,比iphone5页面窄的就把网页缩小。比如iPhone6的手机屏幕宽度是iphone5的1.17倍,就通过js把整个网页放大1.17倍。酱紫在iphone5上表现良好的页面在iphone6上就没问题了。具体怎么放大缩小,有两种方法。

    2.1 缩放html元素,使用transfrom的scale属性或者zoom属性。

    2.1 使用meta标签的 initial-scale、minimum-scale和maximum属性

看到这里,你可能有个疑问,为啥我们都是根据宽度去调整页面而不是根据高度啊。根据我抄袭别人的经验,高度调整是比较容易的,给底部的元素一个bottom定位就可以。不行你就往中间挤挤喽,我说的方法只是讲原理,你要是想做的完美还要灵活运用

如果你看完序言的1、2点,恭喜你,你已经掌握掌握了移动端适配的九阳神功了。下面就是打通任督二脉的时候,骨骼惊奇的人可以飘过。

1.rem单位值缩放法

ps:这名字是我起的。

1.1 rem是什么

w3c定义:font size of the root element

翻译一下:rem为根元素的字体大小。网页的根元素就是html元素,所以rem就是html元素的字体大小。

假设html字体大小16px,那么1rem就是16px。假设html字体大小为10px,那么1rem就是10px。

1.2 rem值与设计稿之间的关系

1.2.1设计稿尺寸

移动端的设计稿一般都是以iphone5为准设计的,为了显示清晰,设计稿的尺寸通常是屏幕尺寸的两倍。比如iphone5的尺寸是320x568,所以设计稿一般640x1136。根据情况的不同,设计稿也有640x1008和640x960的。高度比较容易调整,宽度能保证是两倍就可以啦。

因为设计稿是以iphone5为准设计的,所以我们制作的时候最好也是以iphone5为准,这样比较好计算。其他屏幕只要我们页面进行放大和缩小就能达到适配的效果。

1.2.2设置rem值的大小

因为我们是采用rem单位值缩放法,所以首先要确认一点,1rem值要等于多少px比较合适。其实这里就比较随意了,你爱设置成多少就可以设置成多少。当然从实际应用的角度出发,把rem值设置成10px或者100px会比较好,因为计算方便。我们这里以1rem等于10px为例

此时我们需要在页面添加如下css

html{
  font-size:10px;
}

因为所有的浏览器默认字体大小都是16px,所以我们也可以设置html的fontsize为62.5% (10/16*100%);

html{
  font-size:62.5%;
}

这样我们1rem就是10px了。

ps,默认情况下浏览器允许的最小字体是12px,即使你把字体设置成10px,浏览器还是按照12px来显示。为了解决这个问题,需要你在html上设置一个样式;

html{
  text-size-adjust:none;
  -webkit-text-size-adjust:none;
}

 

1.2.3rem值与设计稿的对应关系

因为1rem=10px。所以把px转化为rem的时候,只要把px的值除以10再把单位由px转为rem就可以了。对应到设计稿上的话,因为设计稿尺寸是屏幕尺寸的2倍,所以把设计稿上的元素尺寸由px转化为rem的时候是除以20(先把设计稿缩小2倍,使设计稿跟屏幕尺寸一样大,再除以rem和px10倍的对应关系)。假设设计稿上有个图片宽高是100px,对应的rem值就是5rem(100/2/10)。

1.2.4rem值与px的对应关系。

其实这一点不用讲了,1rem就是10px。但是避免1.2.3有误导,所以特别说明下。

假设你是在chrome开发者工具上,设置个元素的宽高为100px。那么转化成对应的rem就是10rem(100/10)而非5rem(100/2/10)。因为此100px相对的是320px的屏幕而非640的设计稿,所以不用再除以2了。

1.2.5其他屏幕的适配

经过前面的4点,你的设计稿在iPhone5上应该已经能正常显示了。此时你用iphone6看的话,你的页面可能错乱了。因为你还没有在iphone6对页面做适配,也就是你在iPhone6下还没有修改rem对应的px值的大小。

1.2.5.1使用js修改rem值的大小

这个方法比较简单,获取其他手机屏幕相对于iphone5手机屏幕的大小,然后放大和缩小html的fontsize值就可以了。这个方法有个缺点就是fontsize值可能为小数,有可能导致页面上的文字出现模糊不清的情况。只要微调下就可以并不是大的问题。js代码如下:

(function(){
  var scale = window.innerWidth/320;
  document.documentElement.style.fontSize = 10*scale+"px";
})()

使用上面这段代码是有前提的,就是页面必须要加这段html代码。

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

原因如下:

在移动端的发展过程中,早期的手机为了正常显示pc页面,手机默认的viewport的宽度并不是手机屏幕的宽度,一般默认的viewport宽度为980px,当然也有手机默认的宽度为1280px。这样如果你不把viewport的宽度设置为device-width的话,window.innerWidth就是默认值980px或者是1280px。这样我们上一段代码就有问题了。我们使用window.innerWidth获取的并不是屏幕的宽度,所以求出来的scale也就错了。

解决方法有两个,一个是加上meta那一段html代码,既设置viewport的width为device-width。推荐使用这个方法(其实现在的移动端页面都有这段代码)。第二个方法就是改用screen.width而不是使用window.innerWidth。

var scale = screen.width/320;
 点击参看demo
1.2.5.2使用媒体查询适配

使用媒体查询设置html元素font-size的大小。这个方法简单但是工作量较多,一来是需要知道市场上所有主流的手机的屏幕尺寸,二来如果未来出现新的机型号到时候可能又会出现页面不适配的情况。当时这个方法确实比较简单一点,媒体查询的css如下:

html{
  font-size:62.5%;
}
@media screen and (min-width:360px) and (max-width:374px) and (orientation:portrait) {
    html { font-size: 70.3%; }
}
@media screen and (min-width:375px) and (max-width:383px) and (orientation:portrait) {
    html { font-size: 73.24%; }
}
@media screen and (min-width:384px) and (max-width:399px) and (orientation:portrait) {
    html { font-size: 75%; }
}
@media screen and (min-width:400px) and (max-width:413px) and (orientation:portrait) {
    html { font-size: 78.125%; }
}
@media screen and (min-width:414px) and (max-width:431px) and (orientation:portrait){
    html { font-size: 80.86%; }
}
@media screen and (min-width:432px) and (max-width:479px) and (orientation:portrait){
    html { font-size: 84.375%; }
}
//以下为ipad分辨率
@media screen and (min-width:480px)and (max-width:639px) and (orientation:portrait){
   html{ font-size:93.75%;}
}
@media screen and (min-width:640px) and (orientation:portrait){
   html{ font-size:125%;}
}

点击参看demo

1.3 总结

rem单位值缩放法,原理上很简单,就是让1rem对应的px值根据屏幕的不同而不同。在某一个屏幕上页面做好效果后,在其他屏幕上显示的时候,再根据该屏幕相对于标准屏的大小,对rem值进行放大和缩小。其中通过js修改rem的方法,最简单也最好用,在不同的屏幕下表现也很好。

2.网页缩放法。

这里对css的单位要求就不大了,你可以使用rem(这里1rem对应的px值不同屏幕下是不变的),也可以使用px。当时使用rem是比较好的。因为使用rem你可以方便切换其他适配方法

2.1如何制作设计稿

这其实没啥可讲的啦,就跟普通的pc端制作页面一样。不过还是有要点要提醒下的,如果你是640的设计稿你就在iphone5下制作,如果你是750的设计稿你就iphone6制作。制作完后,你喜欢的话就可以把px转成rem,不喜欢的话就用px。至于怎么选择主要还是看你周围妹子的颜值了。

2.2使用css属性对网页进行缩放

这里的css属性是指css的zoom属性而不是transform的scale属性,因为zoom跟scale还是有些不同的,最简单的有两个,1个是zoom的缩放是以左上角为基点的,而scale是以元素的中心为基点,第二个不同是zoom是真实的对元素进行放大和缩小,而scale仅仅只是缩放外观,元素实际大小并没有改变。

假设设计稿还是640px,我们在iphone5制作完页面以后,为了达到兼容其他手机屏幕的效果。我们要在页面加一段js,这段js的作用是获取屏幕的宽度,然后与iphone5屏幕尺寸进行比较,如果比iphone5屏幕大, 我们就放大页面,如果比iphone5屏幕小我们就缩小页面。放大和缩小页面其实就是放大和缩小html元素。也可以放大或者缩小body元素,不过缩放body元素有bug,html小body大就会溢出,body小html大,底部会有空白。所以缩放html元素是最好的。

(function(){
	var zoom = screen.width/320;
  	document.documentElement.style.zoom=zoom;
})();

点击参看demo

2.3使用meta标签的网页缩放法

除了使用css属性对页面缩放外,我们还可以使用name为viewport(视窗)的meta标签对页面进行缩放,该标签是苹果公司最先在浏览器中实现的,不过现在已经得到了几乎所有移动端浏览器的支持。为了不打脸我加了“几乎”,其实你见到的浏览器都支持这一属性,所以大胆的用吧,不用担心。

name为viewport(视窗)的meta标签有以下属性

width 视窗的宽度
initial-scale 设置页面的初始缩放值,为一个数字,可以带小数
minimum-scale 允许用户的最小缩放值,为一个数字,可以带小数
maximum-scale 允许用户的最大缩放值,为一个数字,可以带小数
height  设置视窗 的高度,这个属性对我们并不重要,很少使用
 user-scalable  是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes代表允许

 

 

 

 

其中initial-scale、minimum-scale和maximum-scale属性就是页面进行放大和缩小的。我们常见的meta是酱紫的。视窗的width为device-width(设备的屏幕宽度),最小放大倍数和最大放大倍数都是1,也就是不允许页面进行放大和缩小。

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

添加这种meta标签的页面都是使用rem单位值缩放法进行适配的。现在我们要使用网页缩放法就需要对这个meta标签进行修改,可以使用js获取该meta标签然后使用setAttribute进行修改,也可以使用js直接write出该meta标签。我使用直接write的方法,这样比较简单。切记这段js要加载head标签里。

(function(){
	var scale = screen.width/320;
  	document.write('<meta name="viewport" content="width=320,minimum-scale='+scale+',maximum-scale='+scale+'">')
})()

上面的代码有两2个要特别注意,第一个地方是求scale的时候,使用的是screen.width/320。而不是window.innerWidth。第二个地方上是viewport的width我们是固定的就是320。而不是device-width。

先解释第二地方,因为我们是在iphone5下制作页面,对于其他屏幕,我们是比较它相对于iphone5页面的大小,再对iPhone5的页面进行放大和缩小。所以我们viewport的width就不能跟随屏幕的不同而不同,就必须固定为iphone5的屏幕宽度。

再解释第一个地方。如果viewport的width不是device-width那么window.innerWidth获取的就不是屏幕的宽度。在我们js代码之前也没还没有meta的所以此时使用window.innerWidth获取的是浏览器的默认的viewport宽度980或者1280px。

点击查看demo

2.4总结

网页缩放法的原理是,以一个手机(通常是iphone5)为基准,在其他手机上显示的时候,通过js获取手机屏幕宽度,然后与基准手机进行对比,使用css属性或者meta标签对页面击进行缩放。网页缩放法在实际应用中并不多。在实际应用中更多的使用rem单位值缩放法。不过这两种方法确实也非常好用。

3.Canvas适配。

做游戏的时候,我们几乎都是在canvas上进行制作的,这时候就要面临一个问题就是canvas如何做适配。看起来很难,其实很简单了。不过我当初也是花了好几个星期才弄懂。那还是在我学习createjs的时候。虽然我现在都没学会createjs,但是我研究了下如何在canvas下做适配,还是有点收获的。canvas做适配原理同dom是一样的,都是对页面进行放大和缩小。原理这东西看起来都是像句废话一样,但是真要会应用了你就会发现,这就是一大杀器啊。你掌握某个技能你只能处理一个问题,但是你掌握了原理你就能通杀一大片。

3.1 canvas的缩放

canvas的缩放业界通用的做法是对canvas样式的宽和高(注意注意:这里说的是canvas的style属性的宽和高,而不是canvas的宽和高)进行缩放的。当然缩放的方法很多了你也可以想象其他歪点子。鉴于我已经写的很烦了,哎,主要是人老体弱多病,我就只介绍下宽高缩放法。

canvas页面制作的时候还是以一个手机为基准,640的手机就以iphone5为准,750的手机就以iphone6为准。比如我是以iphone5为准的。那么我的canvas就可以这样写

<canvas id="myC" width="320" height="568"></canvas>

此外你还要定义一些css样式,因为canvas是行内元素,行内元素与行内元素之间默认是3-5px的间距的。虽然我们只在body中放了一个canvas元素,但实际上我们的body中还用空格,空格也是行内元素。所以如果直接把canvas放在body里是有一点点问题的。在iphone5下canvas“看起来”好像偏大了,导致页面出现了向下的滚动条。刚才已经说了,这个问题是由于行内元素有个默认的间距引起的,所以只要去掉间距就可以了,解决方法就是设置body的font-size为0。

css样式如下:

html,body{
  margin:0px;
  padding:0px;
  background:black;
  font-size: 0px;
  width: 100%;
  height: 100%;

}
canvas{
  position: absolute;
  background: white;
}

3.1.1以宽度为准,保持原始宽高比缩放canvas

在这种情况下,不同的手机查看网页,宽度都是可以正好铺满屏幕,高度的话如果屏幕过长,canvas下就会有空白,如果屏幕过短,页面就会出现滚动条。

适配的代码如下:

var can = document.getElementById("myC");
var canW=320;
var canH=568;
var canStyleW = screen.width;
var canStyleH = screen.width/(canW/canH);
can.style.width = canStyleW+"px";
can.style.height = canStyleH+"px";

点击查看demo

3.1.2以高度为准,保持原始宽高比缩放canvas

在这种情况,在不同的手机查看网页,在高度上网页会始终铺满屏幕的,但是在宽度上,如果手机屏幕过宽,就会出现空白。如果屏幕过窄,就会出现滚动条。以下代码,我这对canvas加了居中处理。

适配代码如下:

var can = document.getElementById("myC");
var canW=320;
var canH=568;
var canStyleW = screen.height*(canW/canH);
var canStyleH = screen.height;
can.style.width = canStyleW+"px ";
can.style.height = canStyleH+"px ";
can.style.left = (screen.width-canStyleW)/2+"px";

点击查看demo

3.13根据屏幕宽高比缩放canvas

在这种情况下,我们要获取屏幕的宽高比,然后跟iphone5的宽高比进行比较,大的话说明屏幕宽度较大高度较小,可能导致我们的canvas显示不全而出现上下滚动条,这时我们就以高度为准进行适配。小的话说明屏幕宽度偏小高度偏大,这样就有可能导致左右方向上显示不全。所以我们要以宽度为准进行适配。我们的目的只有一个,就是只在一屏上完整的显示出我们的canvas。

适配代码如下:

var can = document.getElementById("myC");
var canW=320;
var canH=568;
var ratio= canW/canH;
var screenRatio = screen.width/screen.height;
var canStyleW,canStyleH;
//宽度偏大,以高度为准
if(screenRatio>=ratio){
  canStyleW = screen.height*ratio;
  canStyleH = screen.height;
}else{
  //高度偏大,以宽度为准
  canStyleW=screen.width;
  canStyleH=screen.width/ratio;
}
can.style.width = canStyleW+"px ";
can.style.height = canStyleH+"px ";
can.style.left = (screen.width-canStyleW)/2+"px";

点击参看demo

3.2总结

canvas适配也是采用放大和缩小,原理都很简单。当然我以上示例中的适配方案还是很粗糙的,在实际开发环境中肯定是要优化的。我只是为了将原理,所以并没有给一个完整的方案。当然我只讲了一个适配方案,肯定还有其他适配方案的,或者更好的适配方案肯定也是有的。还是那句话,原理都一样,如果运用原理就是你的事情了。

4、大总结:

移动端屏幕适配的大概就这些内容,要么对元素进行放大缩小,要么对网页进行放大缩小。不知道你看明白了没,不过我个人倒是很明白了,没写着博客前我还是糊里糊涂的,哈哈,目的达到了。移动端适配真的没有那么难。希望这篇博客对你有帮助。ps一句话,有问题自己多动手写代码,实践出真知。

 

posted on 2017-06-30 18:14  强大大  阅读(1533)  评论(0编辑  收藏  举报