如何处理跨平台的自适应二
相信大家在面试的过程中总会被问到如何处理自适应这样的相关问题,自适应其实就是根据视口的大小或者说用户平台的不同呈现出不同或相同的样式,有这么几种方案:
- 使用flexbox弹性布局的方法
- 固定一个某些宽度,使用一个模式,加上少许的媒体查询方案
- 使用rem
---------------------------分------------割-------------------------------------
固定某些宽度(百分比)+媒体查询
我们知道其实Bootstrap的核心就是媒体查询的技术实现响应式布局,在iphone6下的布局是什么样的,在iPad下布局是怎么样的,在pc端布局又是一个样子,如此而已。
但是在移动网络发展如此兴盛的今天,移动端的Web开发也更加多样化。在做PC端时,我们可以设置一个合理的内容宽度,然后让它居中显示。这样基本上可以解决所有分辨率的显示器。但是在面对丰富尺寸的移动端时,Iphone、安卓各种屏幕分辨率,使用百分比宽度布局这种方法,在实际项目中做适配的时候非常麻烦,要么是在iphone6图标看上去太大了,要么就是在iphone4上折行了。
解决办法呢,就需要写大量的媒体查询来分别控制不同分辨率上元素的宽度、间距、一些地方的字体大小。我们用模拟器去测试的话,模拟出来的机型还是很有限的。但是在智能手机品牌、机型如此众多的今天,各种不规则的分辨率,我们更难寻找到所有的真机一一去测试。另外用这种方法做出来的页面和设计相比,无论我怎么去调试,都会有比例上的不一样的问题。这就会导致不能很好的还原设计。那么就没有好的办法解决移动端还原设计并且适配不同终端这个问题了吗?
答案当然是有的,那就是使用REM!
使用rem
REM是CSS3新增的一个相对单位(root em,根em),这个单位引起了广泛关注。这个单位与em有什么区别呢?区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。
这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。
目前,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器,应对方法也很简单,就是多写一个绝对单位的声明。这些浏览器会忽略用rem设定的字体大小。当然,IE8在国内市场还有占有相当一部份份额的。就是为什么国外网站大多使用rem,但是在国内确很少见有使用rem的。但是对于移动端不同,现在移动端主要分为IOS 和Android 两大阵营,并且他们的浏览器都是Chrome内核。所以在手机端可以忽略兼容性这个问题。
那么了解了REM之后,使用方法又是什么呢?首先所有浏览器默认字体大小都是16px,那么1rem=16px,但是会发现在实际换算中很麻烦,如果把HTML 的font-size大小设置为62.5%,这样font-size的大小就会等于10px; 也就是说1rem=10px;这样在实际使用过程中会很方便。
在这里我提一个在chrome浏览器上的问题,因为大多数开发人员都会使用Chrome做为调试工具,在中文版的Chrome浏览器上,浏览器最小可识别12Px大小的字体。也就是说当你设置了字体大小小于12像素以下的字体大小时,浏览器都会当做12PX显示出来,对,你没有看错,Chrome就是这么变态,至于为什么,我们也不知道。这里推荐一下根原素以20px做为根据素大小或者使用Firebox做为调试浏览器。这样就不会出现这个问题了。
在iphone6上,我们设置了20px=1rem,但是在iphone4上,同样的1rem,就不应该是20px,而是应该大约17px(为(320/375)*20),这样才可以保证对应的1rem和原来的效果相似,否则,在iphone4就变得很大了。所以,在iphone4上我们要修改html的font-size=17px,可是还有Iphone5, iphone6 plus,还有无数的安卓机型呢,我们该怎么办?
那么理解REM的原理后,有人会有疑问,即使rem是相对大小,那么怎么达到字体大小的响应呢?下面给大家介绍两种方法。
- 第一种是使用媒体查询控制不同分辨率下的根原素大小。方法如下图,要根据项目的实际类型改变媒体查询的值。
- 第二种方法就是通过JavaScript动态获取屏幕的宽度,然后给HTML设置font-size的值。下面我给大家讲解一下这段JS代码。我主要以手机端为例。
将这做代码打包到一个defineRemSize.js的文件中,在页面里引用。在用下面这这个方法调用。
做完了这这些,我们有了可以自适应的rem的值,接下来我就说一下在实际使用中的一些心得。 Rem不仅可以用在字体大小单,包括容器宽度的值、高度的值、margin的值、padding的值都可以使用rem做为单位大小。实际上rem更像是聪明的百分比数值。如果页面所有远素的值都使用rem,整个面更像是一张图片。缩小时整体都会缩小,放大里整体都会放大。下面我给大家看一下我使用两种方法做的同一个页面的效果图。
通过对比,会发现,使用rem在不同分辨率的设备上整体比例是不变的。并且没有使用任何媒体查询方法。但是使用px+%这种方法做出来的页面,在不同的页面上的元素的间距会发生改变,图片会随首设备宽度的变化而变化,但是文字大小以及元素的间距并没有发生变化。
由以上可以得出,在使用rem做为页面元素单位时,在适配时会更加简便,并且页面在不同尺寸的终端设备上页面整体比例不会改变。不需要我们再通过Media query 来适配不同的分辨率。并且做出来的页面会更加的接近设计图。
rem例子
我们借助网易的例子,来了解一下如何使用rem以及他们是怎样处理不同分辨率下根源素的大小的。先来看看网易在不同分辨率下,呈现的效果:
从上面几张图可以看出,随着分辨率的增大,页面的效果会发生明显变化,主要体现在各个元素的宽高与间距。375*680的比320*680的导航栏明显要高。能够达到这种效果的根本原因就是因为网易页面里除了font-size之外的其它css尺寸都使用了rem作为单位,比如你看导航栏的高度设置代码:
可是在本文第1部分提到,使用rem布局结合在html上根据不同分辨率设置不同font-size有很多不好解决的麻烦,网易是如何解决的呢?最根本的原因在于,网易页面上html的font-size不是预先通过媒介查询在css里定义好的,而是通过js计算出来的,所以当分辨率发生变化时,html的font-size就会变,不过这得在你调整分辨率后,刷新页面才能看得到效果。你看代码就知道为啥font-size是直接写到html的style上面的了(js设置的原因):
它是根据什么计算的,这就跟设计稿有关了,拿网易来说,它的设计稿应该是基于iphone4或者iphone5来的,所以它的设计稿竖直放时的横向分辨率为640px,为了计算方便,取一个100px的font-size为参照,那么body元素的宽度就可以设置为width: 6.4rem,于是html的font-size=deviceWidth / 6.4。这个deviceWidth就是viewport设置中的那个deviceWidth。根据这个计算规则,可得出本部分开始的四张截图中html的font-size大小如下:
deviceWidth = 320,font-size = 320 / 6.4 = 50px deviceWidth = 375,font-size = 375 / 6.4 = 58.59375px deviceWidth = 414,font-size = 414 / 6.4 = 64.6875px deviceWidth = 500,font-size = 500 / 6.4 = 78.125px
事实上网易就是这么干的,你看它的代码就知道,body元素的宽是:
根据这个可以肯定它的设计稿竖着时的横向分辨率为640。然后你再看看网易在分辨率为320*680,375*680,414*680,500*680时,html的font-size是不是与上面计算的一致:
320*680
375*680
414*680
500*680
这个deviceWidth通过document.documentElement.clientWidth就能取到了,所以当页面的dom ready后,做的第一件事情就是:
//code from http://caibaojian.com/mobile-responsive-example.html document.documentElement.style.fontSize = document.documentElement.clientWidth / 6.4 + 'px';
这个6.4怎么来的,当然是根据设计稿的横向分辨率/100得来的。下面总结下网易的这种做法:
- (1)先拿设计稿竖着的横向分辨率除以100得到body元素的宽度:
如果设计稿基于iphone6,横向分辨率为750,body的width为750 / 100 = 7.5rem 如果设计稿基于iphone4/5,横向分辨率为640,body的width为640 / 100 = 6.4rem
- (2)布局时,设计图标注的尺寸除以100得到css中的尺寸,比如下图:
- 播放器高度为210px,写样式的时候css应该这么写:height: 2.1rem。之所以取一个100作为参照,就是为了这里计算rem的方便!
- (3)在dom ready以后,通过以下代码设置html的font-size:
document.documentElement.style.fontSize = document.documentElement.clientWidth / 6.4 + 'px';
- 6.4只是举个例子,如果是750的设计稿,应该除以7.5。
- (4)font-size可能需要额外的媒介查询,并且font-size不能使用rem,如网易的设置:
@media screen and (max-width:321px){ .m-navlist{font-size:15px} } @media screen and (min-width:321px) and (max-width:400px){ .m-navlist{font-size:16px} } @media screen and (min-width:400px){ .m-navlist{font-size:18px} }
最后还有2个情况要说明:
第一,如果采用网易这种做法,视口要如下设置:
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
第二,当deviceWidth大于设计稿的横向分辨率时,html的font-size始终等于横向分辨率/body元素宽:
640*680
641*680
之所以这么干,是因为当deviceWidth大于640时,则物理分辨率大于1280(这就看设备的devicePixelRatio这个值了),应该去访问pc网站了。事实就是这样,你从手机访问网易,看到的是触屏版的页面,如果从pad访问,看到的就是电脑版的页面。如果你也想这么干,只要把总结中第三步的代码稍微改一下就行了:
var deviceWidth = document.documentElement.clientWidth; if(deviceWidth > 640) deviceWidth = 640; document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px';
---------------------------分------------割-------------------------------------
以上内容摘自
流云诸葛——从网易与淘宝的font-size思考前端设计稿与工作流
感谢大神们的实践总结~