做移动端页面有一段时间了,总结一下工作中常用的几种移动端适配方案。基础网站上已经有很多基础知识总结,这里不再赘述。详情见《关于移动端适配,你必须要知道的》《不要再问我移动适配的问题了》。容易混淆的概念是viewportmeta标签中的viewport属性是view的意思Viewport分为layoutviewportVisualviewportidealViewportlayoutviewport是我们在css中写的所有样式默认都是相对布局视口进行布局的,移动端的布局视口不是屏幕宽度,一般在768px~1024px之间(大多数情况下是980px),可以通过document.documentElement.clientWidth获取(根据width和initial-scale决定)VisualViewportVisualViewport指的是用户透过设备屏幕看到的区域。默认情况下,它等于当前浏览器的窗口大小(当initial-scale为1时)。当用户缩放浏览器时,布局视口的大小不会改变,所以页面布局不会改变,但缩放会改变视觉视口的大小。可以通过window.innerWidth获取(会随着缩放而改变)来放大页面。这时候window.innerWidth反而会变小(页面放大了,你看到的东西变少了)理想视口理想视口是指网站在移动设备上的理想尺寸。这个size就是设备的屏幕尺寸,也就是中device-width的意思,可以通过screen.width获取(常量,不会改变)initial-scale根据公式initial-scale=IdealViewportWidth/VisualViewportWidth假设理想视口宽度为414px(device-width),那么设置initial-scale为0.5,则视觉视口宽度为414/0.5=818如果得到document的值.documentElement.clientWidth(布局视口),你会发现不是414px而是818px。结论:布局视口的宽度为width和视觉视口宽度的最大值思考题:假设理想的视口宽度为414px(device-width),document.documentElement.clientWidth(layoutviewport)的值是多少?visualviewport=414/2=207layoutviewport=Math.max(207,600)layoutviewport=600总结document.documentElement.clientWidth:布局视口,在css中一般写为width=device-widthwindow.innerWidth:视觉视口,页面缩放会实时变化值screen.width:idealviewport,页面屏幕尺寸(设备无关像素),也就是css中device-width常见的适配方案简单一句话概括:移动端适配是按比例缩放屏幕宽度:我们在开发过程中通常会拿到尺寸为750*1334(iPhone6的设备像素为标准设计图)的手机设计稿。如果在750px的设计稿上测得的元素宽度是100px,那么在375px宽度的屏幕下,这个元素的宽度应该按比例缩放到50px。所以适配的难点在于:如何实现页面的比例缩放?rem方案该方案的核心是:所有需要动态布局的元素不再使用px固定尺寸,而是使用rem的相对尺寸。rem的大小是相对于根元素html的字体大小而言的:如果html的font-size为100px,那么1rem就等于100px现在我们假设:750px屏幕下html的font-size为100px,即即,1rem为100px,那么宽度为200px的.box元素应该写成2rem.box{/*750pxscreen,200px*/width:2rem;}现在:375px屏幕,我们需要的.box元素为renderedas100px.box{width:2rem;}由于.box的宽度还是2rem,所以这个时候我们需要1rem为50px,也就是说,这个时候html的font-size是50px,所以这个时候,我们可以得出一个公式:(750)/(100)=(当前屏幕尺寸)/(当前屏幕1rem)并把这个公式进行数学换算。得到:(当前屏幕1rem)=100*(当前屏幕尺寸)/750翻译成js语言就是document.documentElement.style.fontSize=100*(document.documentElement.clientWidth)/750+'px';优化代码constPAGE_WIDTH=750;//设计稿的宽度constPAGE_FONT_SIZE=100;//设计稿的大小1remconstsetView=()=>{//设置html标签的字体大小document.documentElement.style.fontSize=PAGE_FONT_SIZE*(document.documentElement.clientWidth)/PAGE_WIDTH+'px';}window.onresize=setView;//如果窗口大小发生变化,就会触发setView事件。setView()考虑到Android端字体渲染的问题和页面大小变化的监听,最后代码如下:(function(){vartimer=空;变种PAGE_WIDTH=750;//设计稿的宽度varPAGE_FONT_SIZE=100;//设计稿的大小1remfunctiononResize(){vare=PAGE_FONT_SIZE*document.documentElement.clientWidth/PAGE_WIDTH;文档.documentElement.style.fontSize=e+'px';//计算两次缩放像素,解决移动webkit字体缩放bugvarrealitySize=parseFloat(window.getComputedStyle(document.documentElement).fontSize);如果(e!==realitySize){e=e*e/realitySize;document.documentElement.style.fontSize=e+'px';}}window.addEventListener('resize',function(){if(timer)clearTimeout(timer);timer=setTimeout(onResize,100);});onResize();})();注:我们取100px作为设计稿的1rem,方便计算。比如我们在设计稿上测量250px,我们可以很容易算出为2.5rem,当然我们也可以用50px作为设计稿的1rem。这时候设计稿上的250px一定要写成5rem。其实我们也可以使用postcss-pxtorem或者SCSS函数来帮我们自动转换单位@functionpx2rem($px){//根元素的字体为100px@return$px/100*1rem;}.box{width:px2rem(200);}通过rem方案,需要动态缩放的元素,我们使用rem相对单位,不需要缩放的元素,我们仍然可以使用px固定单位。但是在大屏设备下(比如ipad或者pc),由于我们的页面是按比例缩放的,所以此时页面的元素会放大很多(屏幕宽度大,导致根元素字体也1rem变大)。但是在大屏幕上,我们真正希望的是用户可以看到更多的内容。这时候我们可以使用媒体查询来限制根元素的字体,防止元素在大屏幕上过大的问题。@mediascreenand(min-width:450px){html{font-size:50px!important;}}或者修改js脚本的逻辑constPAGE_WIDTH=750;//designdraftwidthletPAGE_FONT_SIZE=100;//designdraftthesizeof1remconstsetView=()=>{if(document.documentElement.clientWidth>450){//减少大下根元素的字体屏幕PAGE_FONT_SIZE=50;}document.documentElement.style.fontSize=PAGE_FONT_SIZE*(document.documentElement.clientWidth)/PAGE_WIDTH+'px';}VW方案vw是相对单位,1vw表示屏幕宽度的1%其实我们的REM方案就是模拟VW方案,我们之前有一个公式:(750)/(100)=(当前屏幕尺寸)/(当前屏幕1rem)对于另一种换算方法:(当前屏幕1rem)=(当前屏幕尺寸)/7.5和vw单位其实是:(当前屏幕1vw)=(当前屏幕尺寸)/100所以,REM方案是用JS把屏幕宽度分成7.5份,而CSS3中新的vw单位原生实现把屏幕宽度分成7.5份100个零件。因此,在VW方案中,我们不再需要使用JS脚本!在750px的设计稿中,1vw等于7.5px(750/100)。所以在设计稿中,测量200px的宽度是因为写成26.667vw(200/7.5).box{/*750pxscreen,200px*/width:26.667vw;}但是,使用vw转换并不如像rem一样方便。这时候我们可以使用postcss-px-to-viewport或者SCSS函数来帮我们自动转换单位@functionpx2vw($px){@return$px/750*100vw;}.box{width:px2vw(200);}同理,在大屏设备下,由于屏幕宽度大,所以页面的元素是一样的这样会放大很多(屏幕宽度很大,1vw也很大),但是因为vw是相对于屏幕宽度的,所以我们不能像REM方案那样手动控制html的根字体大小,这也是一个使用大众解决方案的缺点。REM+VW方案REM方案的优点是可以手动控制rem的大小,防止屏幕过大时页面元素被过度缩放,缺点是需要JS。VW的解决方案恰恰相反,不需要使用JS但是无法手动控制vw的大小。事实上,我们可以将两者结合起来:html{/*750pxdesign,1rem=100px*/font-size:calc(100*100vw/750);}.box{/*750pxscreen,200px*/width:2rem;对于布局元素,我们仍然使用rem单位。但是对于根元素的字体大小,我们不需要使用JS动态计算100*(document.documentElement.clientWidth)/750。这个js可以直接使用css来实现calc(100*100vw/750)为大屏幕设备,我们使用媒体查询@mediascreenand(min-width:450px){html{font-size:calc(50*100vw/750);}}更详细的vw+rem布局方案可以参考viewportscalingscheme有一个更简单粗暴的方法,就是我们设置initial-scale。我们的布局完全基于设计稿750px,布局元素单位也采用固定的px单位(布局视口硬编码为750px)。对于375px的宽度,我们将整个页面缩放0.5:demo.box{width:200px;}这种方案的缺点:整个页面缩放,不想缩放的元素无法控制市场上的一些营销由于H5页面是通过后台视觉拖拽构建,为适配各种尺寸的屏幕,本方案是成本最低的实现(一奇秀采用本方案)。以rem方案、vw方案、rem+vw方案、viewport方案为例,请使用chrome开发者工具模拟移动设备查看源码,直接右键查看。代码没有压缩,可以直观的看到各种方案的css适配,供参考移动端适配有哪几种方案?不要再问我移动适配的事了。关于移动适配,你必须知道的是基于vw等viewport视口单元和rem响应式排版布局。