移动和pc网页布局适配多设备
一.视口(viewport)
viewport视口
viewport是严格的等于浏览器的窗口。viewport与跟viewport有关的meta标签的关系,详细建议读一读这篇文章:移动前端开发之viewport的深入理解,viewport与布局的关系,可以看下这篇文章:在移动浏览器中使用viewport元标签控制布局
visual viewport 可见视口 屏幕宽度
layout viewport 布局视口 DOM宽度
ideal viewport 理想适口:使布局视口就是可见视口
设备宽度(visual viewport)与DOM宽度(layout viewport), scale的关系为:
(visual viewport)= (layout viewport)* scale
获取屏幕宽度(visual viewport)的尺寸:window. innerWidth/Height。
获取DOM宽度(layout viewport)的尺寸:document. documentElement. clientWidth/Height。
设置理想视口:把默认的layout viewport的宽度设为移动设备的屏幕宽度,得到理想视口(ideal viewport):
我们进行网页布局的时候设置html元素宽度为100%,这个100%是依据什么设置的呢?浏览器窗口用CSS像素衡量的宽度(window.innerWidth)还是别的呢?我们可以发现在PC端的浏览器上设置100%,html元素的px宽度就等于浏览器宽度;而在移动端不管是在什么设备上,html设置100%,基本上宽度都等于980px,这里的980px就是移动端所谓的布局视口了。
在移动端,默认的情况下,布局视口的宽度是要远远大于浏览器的宽度的。这两个视口不同于PC端,是相互独立存在的。浏览器厂商为了让用户在小屏幕下网页也能够显示地很好,所以把布局视口宽度设置地很大,一般在768px ~ 1024px之间,最常见的宽度是980px。这个宽度可以通过document.documentElement.clientWidth得到。
移动端布局需要达到的效果
我们希望一个网页放到移动端的浏览器中不会影响视觉效果,然后又利于开发。所以最好的方法就是设置布局视口的宽度正好等于屏幕的大小(这里的大小是指视觉上的而不是CSS像素单位上的,意思就是比如375的屏幕宽度下,将布局视口设置为屏幕宽度,也就是device-width,CSS像素横向有375个单位,设置375px即可满屏;如果将布局视口设置为设备宽度的两倍即750px,面积增大4倍,同时设置initial-scale为0.5,面积又缩小四分之一正好又是屏幕的大小。),这样的效果就是设置100%的时候保证就是屏幕宽度。(说的比较啰嗦)
如何设置布局视口呢?
<!--设置布局视口等于device-width--><metaname="viewport"content="width=device-width"><!-- 只设置缩放值也能将布局视口宽度设置为屏幕宽度,设置为0.5时由于CSS像素缩放了0.5,填到屏幕中的CSS像素数量正好是屏幕宽度 --><metaname="viewport"content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"><!-- 这是兼容写法 --><metaname="viewport"content="width=device-width,initial-scale=1, maximum-scale=1,user-scalable=no">
二、移动适配方案
移动多屏幕适配是为了保证各个屏幕上的布局视口都是等于屏幕(视觉上的)宽度。所以就有几种方案可以做到。
第一种方案
第一种方案是直接设置width=device-width,这样能够保证宽度一致,但考虑到苹果的Retina屏幕设计师出设计稿的时候都是放大了一倍设计稿,比如640px(基于iphone5)、750px(基于iphone6)。如果我们拿到的设计稿是750px宽,在设置缩放比为100%、布局视口等于屏幕宽度的情况下,我们拿到的设计稿宽度是大了一倍的,(网页中设置375px沾满屏幕,而设计稿切出的图是750px),所以在转换成网页的时候设置宽度需要将设计图的宽度除以2来,如果考虑到iphone6 plus的dpr为3,要保证在6 plus下图片还是高清,就需要将750px的设计稿再放大1.5倍,用@3倍图切出来。以上可以知道这种方案不需要动态的去根据屏幕dpr不同来设置meta标签内容,直接一句话搞定,然后需要调整的地方通过媒体查询来做。
第二种方案
第三种方案就是淘宝的flexible了。这个解决方案只解决苹果设备上的dpr为2和3的情况,不考虑安卓设备也不考虑pad。做的事情也很简单,就是动态设置meta标签的内容,和第一种方案不同的是没有设置为width=device-width,而是通过设置initial-scale来缩放布局视口,dpr为1,缩放为1;dpr为2,缩放0.5;dpr为3,缩放0.3333;通过这种方法使得布局视口在视觉上还是屏幕大小但CSS像素数量却增加了4倍/9倍。而这样的直接好处就是比如iphone6的视觉视口横向有了750个CSS像素点,和设计图保持一致了,同时CSS像素缩放0.5解决了经典的1px像素问题。
该方案的核心原理是通过window.navigator.appVersion判断是否是iphone,其他的比如ipad、Android直接设置dpr为1,然后通过 1/ dpr 得到缩放值。
varisAndroid=win.navigator.appVersion.match(/android/gi);/* 判断iphone ipad不考虑*/varisIPhone=win.navigator.appVersion.match(/iphone/gi);vardevicePixelRatio=win.devicePixelRatio;if(isIPhone){// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案if(devicePixelRatio>=3&&(!dpr||dpr>=3)){dpr=3;}elseif(devicePixelRatio>=2&&(!dpr||dpr>=2)){dpr=2;}else{dpr=1;}}else{// 其他设备下,仍旧使用1倍的方案dpr=1;}/*缩放值*/scale=1/dpr;
这个解决方案中用的布局单位是rem而不是px,这也是为了等比例缩放的问题。rem单位代表的是根节点也就是html的fontSize的值,html默认为16px,所以默认1rem = 16px。既然开发的设计标注图是750px的,将html设为75px就很方便了,10rem = 750px。
然后放到所有屏幕情况下:
functionrefreshRem(){/*获取布局视口宽度,也可用document.documentElement.clientWidth*/varwidth=document.documentElement.getBoundingClientRect().width;/* 判断屏幕宽度,如果dpr为1且宽度>540 则恒定为540px,dpr为2如果宽度>1080则恒定为1080px*/if(width/dpr>540){width=540*dpr;}/*将布局视口宽度除以10得到html字体大小*/varrem=width/10;document.documentElement.style.fontSize=rem+'px';}
比如iphone5的设备下布局视口是640,所以html的字体大小会设置为64px,而在开发的时候设置的单位为rem,这个时候rem自动根据64px转换,就实现了等比缩放。写rem的时候可以通过CSSREM插件来写,只是后期维护比较麻烦。
字体不用rem而采用px是因为我们希望一个文本字号不因为Retina显示屏的原因而缩放变小。然后在大屏上也不会放大而能够看到更多的文本。但是不同的dpr下又的确是要分别设置字号的。这个解决方案会在html元素上设置data-dpr属性,然后通过该属性判断来设置字体大小。
div.box{ font-size: 12px;}[data-dpr="2"] div{ font-size: 24px;}[data-dpr="3"] div{ font-size: 36px;}
如果觉得麻烦可以用sass来写样式,用@mixin。
设计稿设计方面要求为750px,如果设计师有做标注就做在这个稿子上,没有标注的话我们开发的时候就依据这个设计稿来量间距之类的。同时将这个稿子放大1.5倍来得到1125px的设计稿,切图用这份设计稿保证dpr为3的屏幕图片显示足够清晰。在iphone6的屏幕下开发然后再向上向下适配。字体也希望不要出现奇数值,我们都知道为什么。
viewport视口
viewport是严格的等于浏览器的窗口。viewport与跟viewport有关的meta标签的关系,详细建议读一读这篇文章:移动前端开发之viewport的深入理解,viewport与布局的关系,可以看下这篇文章:在移动浏览器中使用viewport元标签控制布局
visual viewport 可见视口 屏幕宽度
layout viewport 布局视口 DOM宽度
ideal viewport 理想适口:使布局视口就是可见视口
设备宽度(visual viewport)与DOM宽度(layout viewport), scale的关系为:
(visual viewport)= (layout viewport)* scale
获取屏幕宽度(visual viewport)的尺寸:window. innerWidth/Height。
获取DOM宽度(layout viewport)的尺寸:document. documentElement. clientWidth/Height。
设置理想视口:把默认的layout viewport的宽度设为移动设备的屏幕宽度,得到理想视口(ideal viewport):
2.替换px转而使用rem
设定父盒子的css为
父盒子{width:320px}
设置根元素的font-size为屏幕的某个比例
html{font-size:16px;}
那么父盒子的css为
父盒子{ width:20rem;//换算为320px,充满屏幕宽度height:10rem;//换算为160px,盒子比例达到1:1}
但是css的替换以及rem的计算还是比较繁琐的,这里建议使用sass的函数
然后使用正则替换
(/(\d+[\.\d+]?px)/g,'rem($1)')
$baiscRem:320px /20//这里假定为页面做20个等分@functionrem($px)@return($px / $basicRem)* 1rem父盒子width:rem(320px)
围观群众1:为什么不在写css时候直接使用rem呢?
答:每次都调尺寸都要用计算器算一下啊,好麻烦。(╯°口°)╯(┴—┴
围观群众2:为什么不直接写 rem(320px) ?
答:写括号也好麻烦。(:3」∠)
然后,使用css @media查询,确定rem的值。
这里就比较具体了,需要根据实际的业务需求来决定所要适配的设备尺寸
/* media.css */@mediascreen and (min-width:320px) and (max-width:320px){html{font-size:320/320* $basicRem; }}@mediascreen and (min-width:400px) and (max-width:400px){html{font-size:400/320* $basicRem; }}
tips:如果不知道要兼容什么样的设备。可以再用户访问后,javascript收集该设备的相关信息,
然后在服务端自动更新该文件的内容,加入新的@media规则。
但是全部使用rem,有个缺点很蛋疼,
就是除法导致的小数缺省的问题,导致视觉上会有几个像素的偏差。
例如:多列布局会引起几个像素的空白等 ( ̄へ ̄)
关于vw,vh
宽高的1%,建议使用在各种布局的容器上,如上图的父盒子和子盒子。
父盒子{box-sizing:border-box;padding:10vw;width:100vw;height:50vw;/* 妥妥的2:1比例 */letter-spacing: -4px;/*消除行内元素的4px的空白间隔 */}子盒子1,子盒子2{magin:05vw;width:30vw;height:30vw;/* 妥妥的1:1的比例 */display:inline-block;}
相比rem,使用vw和wh是非常直观的,让其他人看到就能知道,该界面是以怎么样的结构进行布局,利于维护。
但在具体深入到表现的地方,建议转而使用rem来配合。
注意:vw在一些三星的机子会有兼容问题,导致失效。
如果有兼容问题,vw在容器上的应用可以百分比替换 -->codepen-使用百分比实现的等比例容器
相关链接:
移动端适配方案(主要讲解的是移动端视口方面的知识):
Retina屏幕下模糊的由来:
手淘flexible.js布局: