当前位置: 首页 > 科技观察

适配你需要知道的事—MobileWeb适配总结

时间:2023-03-19 18:28:32 科技观察

开门见山,本文将总结MobileWeb的适配方法,即我们常说的H5页面、手机页面、WAP页面、webview页面等.本文中讨论的页面是指专为移动设备设计的页面,并不兼容所有设备的响应式布局。本文所说的device-width是指viewportmeta标签中width的值,即浏览器指定的值。常见机型的对应值可以参考ScreenSizes。适配效果如何?在不同尺寸的移动设备上,页面“相对实现合理显示(自适应)”或者“保持统一比例缩放(看起来相似)”。适应应关注哪些要素?一般来说,我们需要注意的是:字体、高宽间距、图像(图标、图片)。其中图片相对来说比较复杂,对于流量和清晰度等问题网上也有比较成熟的解决方案,比如:矢量化、字体化、image-set等,这里不再赘述。为了满足快速开发的需要,我们采用偷懒的方式:使用css限制元素内的图片(img图片使用[max-]width:100%,背景图片使用background-size),布局只针对元素。另外,设计者在设计视觉稿时需要考虑采用什么样的宽度,这样既能满足设计本身的需要,又能让前端开发轻松适配切图。为了围绕这三个要素举例,我们用一个小例子来说明接下来要介绍的三种方案的实现。按照640px标准要达到的效果如图:app.jpg固定高度,宽度自适应这是目前最常见的一种方式是自适应布局,将viewportwidth设置为device-width,使用visualdraft以较小的宽度(如320px)作为布局的参考。垂直方向的高度和间距使用固定值,水平方向使用固定值和百分比或使用弹性布局,最终实现“手机屏幕变化时水平拉伸或填充空白的效果”。“图像元素根据容器使用固定值或背景大小进行缩放。简单浏览了一些大厂的主页,比如百度、腾讯、Facebook、Twitter都采用了这种方案。重点:小宽度作为参考是因为如果布局满足小宽度的放置,当屏幕变宽时,简单地填空就可以了;而如果反了,可能会造成“拥挤”,考虑header区域,左边测logo,右边测水平nav。需要一个小宽度的布局和一个大宽度的图像是矛盾的。320px太窄,不利于页面的设计;只能设计水平拉伸的元素布局,有很多局限性。兼容性更好。实现比较简单,style中的大小按照视觉稿的一半大小设置,查看效果和代码。固定宽度,视口缩放mockup,页面宽度,视口宽度使用统一宽度,使用浏览器自身缩放完成适配。页面样式(包括图形元素)完全按照模型的大小进行,使用常量值单位(px、em)。优点:开发简单:把缩放交给浏览器,完全按照视觉稿切图。精准还原:绝对比例缩放,可精准还原视觉稿(不分清晰度)。方便测试:大部分测试可以在PC端完成,部分细节可以在手机端酌情调整(比如图标和字体混合排列时字体不同导致的对齐问题)。存在的问题:像素丢失:对于一些分辨率较低的手机,设备像素可能达不到指定的视口宽度,此时屏幕的渲染可能不准确。边框“消失”比较常见,但随着手机硬件的更新,这种问题会越来越少。缩放失败:部分Android设备不能正常根据meta标签中width的值缩放viewport,需要配合initial-scale。文本换行:存在于缩放无效的模型中。有些手机为了文本阅读方便,文本到达视口边缘(非元素容器的边缘)时会换行。校正视口宽度后,浏览器并没有正确重绘,结果是文本没有填满整行。一些常用的段落文本标签会出现这个问题。缩放失败问题需要通过js动态设置initial-scalevarfixScreen=function(){varmetaEl=doc.querySelector('meta[name="viewport"]'),metaCtt=metaEl?metaEl.content:'',matchScale=元CTT。match(/initial\-scale=([\d\.]+)/),matchWidth=metaCtt.match(/width=([^,\s]+)/);if(metaEl&&!matchScale&&(matchWidth&&matchWidth[1]!='device-width')){varwidth=parseInt(matchWidth[1]),iw=win.innerWidth||width,ow=win.outerWidth||iw,sw=win.screen.width||iw,saw=win.screen.availWidth||iw,ih=win.innerHeight||width,oh=win.outerHeight||ih,ish=win.screen.height||ih,sah=win.screen.availHeight||ih,w=Math.min(iw,ow,sw,saw,ih,oh,ish,sah),scale=w/width;if(ratio<1){metaEl.content+=',initial-scale='+ratio+',maximum-scale='+ratio+',minimum-scale='+scale+',user-scalable=no';}}}文本换行的问题可以通过css样式解决。由于该方案使用固定宽度值,什么是合适的值?首先要考虑的是主流分辨率,可以参考ScreenSizes和友盟指数的数据;其次,考虑设计部门常用的设计尺寸,综合协调,最终确定一个合适的数值。这里使用640px来实现例子,看效果和代码。使用rem布局,根据特定宽度(即html的font-size)设置rem值。页面上任何需要灵活适配的元素都会转为rem进行布局;页面渲染时,会根据页面的有效宽度计算并调整rem的大小,动态缩放,达到适配的效果。使用该方案,还可以根据devicePixelRatio设置initial-scale来放大视口,使页面按照物理像素渲染,提高清晰度。优点:清晰度高,可以达到物理像素的清晰度。可以解决DPR带来的“1像素”问题。向后兼容性更好,即使屏幕宽度增加,PPI增加,该方案仍然适用。缺点:适配js需要尽早进入,减少(避免)视口变化引起的重绘。一些Android机会删除rem的小数部分。需要用于单位转换的预编译库。开发的时候,css和js都是以16px为基础进行rem转换。借助预编译库(以scss为例),我们设置一个动态尺寸单位$ppr:750px/16px/1rem,即pixelperrem,任意弹性尺寸写到哪里:width:100px/$ppr。动态调整rem的方法如下:varfixScreen=function(){varmetaEl=doc.querySelector('meta[name="viewport"]'),metaCtt=metaEl?metaEl.content:'',matchScale=metaCtt.match(/initial\-scale=([\d\.]+)/),matchWidth=metaCtt.match(/width=([^,\s]+)/);if(!metaEl){//REMvardocEl=doc.documentElement,maxwidth=docEl.dataset.mw||750,//每个dpr***页面宽度dpr=isIos?Math.min(win.devicePixelRatio,3):1,scale=1/dpr,tid;docEl.removeAttribute('data-mw');docEl.dataset.dpr=dpr;metaEl=doc.createElement('meta');metaEl.name='viewport';metaEl.content=fillScale(scale);docEl.firstElementChild。appendChild(metaEl);varrefreshRem=function(){varwidth=docEl.getBoundingClientRect().width;if(width/dpr>maxwidth){width=maxwidth*dpr;}varrem=width/16;docEl.style.fontSize=rem+'px';};//...refreshRem();}}代码实现主要参考了淘宝触屏版的适配方法,查看效果和代码,scss的写法可以在这里找到。请注意,较小的背景图片(例如某些图标)的background-size不应使用特定的rem值,因为裁剪后会出现边缘损失。它应该被切割成与元素相同的大小,设置background-size:cover|contain以缩放。总结总的来说,目前还没有完美的解决方案,这些只是通用的解决方案,尽可能满足快速开发和简单适配的需求。其中,一些比较细化的问题(比如字体的点阵大小,定值要求没有弹性)没有讨论。在实际开发过程中,需要综合考虑项目类型、资源成本、人员协调等各种因素,选择合适的方案。代码实现中使用的mobile-util.js集成了固定宽度和rem适配,源码在这里。