flexable-页面自适应方案

flexable-页面自适应方案
痛点虽然H5的页面与PC的Web页面相比简单了不少但让我们头痛的事情是要想尽办法让页面能适配众多不同的终端设备。前端开发完成终端适配方案拿到设计师给的设计图之后剩下的事情是前端开发人员的事了。而手淘经过多年的摸索和实战总结了一套移动端适配的方案——flexible方案。一些基本概念视窗 viewport简单的理解viewport是严格等于浏览器的窗口。在桌面浏览器中viewport就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。移动端的viewport太窄为了能更好为CSS布局服务所以提供了两个viewport:虚拟的viewportvisualviewport和布局的viewportlayoutviewport物理像素(physical pixel)物理像素又被称为设备像素他是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度。正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。设备独立像素(density-independent pixel)设备独立像素也称为密度无关像素可以认为是计算机坐标系统中的一个点这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素)然后由相关系统转换为物理像素。CSS像素CSS像素是一个抽像的单位主要使用在浏览器上用来精确度量Web页面上的内容。一般情况之下CSS像素称为设备独立像素(device-independent pixel)简称DIPs。屏幕密度屏幕密度是指一个设备表面上存在的像素数量它通常以每英寸有多少像素来计算(PPI)。设备像素比(device pixel ratio)设备像素比简称为dpr其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到设备像素比 物理像素 / 设备独立像素在JavaScript中可以通过window.devicePixelRati获取到当前设备的dpr。而在CSS中可以通过-webkit-device-pixel-ratio-webkit-min-device-pixel-ratio和-webkit-max-device-pixel-ratio进行媒体查询对不同dpr的设备做一些样式适配(这里只针对webkit内核的浏览器和webview)。dip或dp,device independent pixels设备独立像素与屏幕密度有关。dip可以用来辅助区分视网膜设备还是非视网膜设备。众所周知iPhone6的设备宽度和高度为375pt * 667pt,可以理解为设备的独立像素而其dpr为2根据上面公式我们可以很轻松得知其物理像素为750pt * 1334pt。meta标签meta标签有很多种而这里要着重说的是viewport的meta标签其主要用来告诉浏览器如何规范的渲染Web页面而你则需要告诉它视窗有多大。在开发移动端页面我们需要设置meta标签如下metanameviewportcontentwidthdevice-width, initial-scale1, maximum-scale1代码以显示网页的屏幕宽度定义了视窗宽度。网页的比例和最大比例被设置为100%。CSS单位rem在W3C规范中是这样描述rem的:font size of the root element.简单的理解rem就是相对于根元素html的font-size来做计算。而我们的方案中使用rem单位是能轻易的根据html的font-size计算出元素的盒模型大小。而这个特色对我们来说是特别的有益处。前端实现方案了解了前面一些相关概念之后接下来我们来看实际解决方案。在整个手淘团队我们有一个名叫lib-flexible的库而这个库就是用来解决H5页面终端适配的。flexible.js是什么flexible.js适配方案采用rem布局根据屏幕分辨率大小不同调整根元素html的font-size从而达到每个元素宽高自动变化适配不同屏幕Vue中怎么用安装cnpm i lib-flexible -S引入import lib-flexible/flexible在main.js你懂得执行这个JS后会在html元素上增加一个data-dpr属性以及一个font-size样式。JS会根据不同的设备添加不同的data-dpr值比如说2或者3同时会给html加上对应的font-size的值。如此一来页面中的元素都可以通过rem单位来设置。他们会根据html元素的font-size值做相应的计算从而实现屏幕的适配效果。除此之外在引入lib-flexible需要执行的JS之前可以手动设置meta来控制dpr值如metanameflexiblecontentinitial-dpr2/其中initial-dpr会把dpr强制设置为给定的值。如果手动设置了dpr之后不管设备是多少的dpr都会强制认为其dpr是你设置的值。在此不建议手动强制设置dprflexible.js首先会获取设备型号然后根据不同设备添加不同的data-dpr值实际上只对iOS设备进行dpr的判断对于Android系列始终认为其dpr为1。if(!dpr!scale){varisAndroidwin.navigator.appVersion.match(/android/gi);varisIPhonewin.navigator.appVersion.match(/iphone/gi);vardevicePixelRatiowin.devicePixelRatio;if(isIPhone){// iOS下对于2和3的屏用2倍的方案其余的用1倍方案if(devicePixelRatio3(!dpr||dpr3)){dpr3;}elseif(devicePixelRatio2(!dpr||dpr2)){dpr2;}else{dpr1;}}else{// 其他设备下仍旧使用1倍的方案dpr1;}scale1/dpr;}屏幕尺寸不同随着rem也不一样如果盒子为150px则转换成15remvarwidthdocEl.getBoundingClientRect().width;varremwidth/10;快速转换插件VS code中可以下载一个插件cssremflexible的实质flexible实际上就是能通过JS来动态改写meta标签代码类似这样varmetaEldoc.createElement(meta);varscaleisRetina?0.5:1;metaEl.setAttribute(name,viewport);metaEl.setAttribute(content,initial-scalescale, maximum-scalescale, minimum-scalescale, user-scalableno);if(docEl.firstElementChild){document.documentElement.firstElementChild.appendChild(metaEl);}else{varwrapdoc.createElement(div);wrap.appendChild(metaEl);document.write(wrap.innerHTML);}事实上他做了这几样事情动态改写meta标签给html元素添加data-dpr属性并且动态改写data-dpr的值给html元素添加font-size属性并且动态改写font-size的值把视觉稿中的px转换成rem读到这里大家应该都知道我们接下来要做的事情就是如何把视觉稿中的px转换成rem。在此花点时间解释一下。首先目前日常工作当中视觉设计师给到前端开发人员手中的视觉稿尺寸一般是基于640px、750px以及1125px宽度为准。正如文章开头显示的示例设计稿他就是一张以750px为基础设计的。那么问题来了我们如何将设计稿中的各元素的px转换成rem。目前Flexible会将视觉稿分成100份主要为了以后能更好的兼容vh和vw而每一份被称为一个单位a。同时1rem单位被认定为10a。针对我们这份视觉稿可以计算出1a7.5px 1rem75px那么我们这个示例的稿子就分成了10a也就是整个宽度为10remhtml对应的font-size为75px。这样一来对于视觉稿上的元素尺寸换算只需要原始的px值除以rem基准值即可。例如此例视觉稿中的图片其尺寸是176px * 176px,转换成为2.346667rem * 2.346667rem文本字号不建议使用rem前面大家都见证了如何使用rem来完成H5适配。那么文本又将如何处理适配。是不是也通过rem来做自动适配?显然我们在iPhone3G和iPhone4的Retina屏下面希望看到的文本字号是相同的。也就是说我们不希望文本在Retina屏幕下变小另外我们希望在大屏手机上看到更多文本以及现在绝大多数的字体文件都自带一些点阵尺寸通常是16px和24px所以我们不希望出现13px和15px这样的奇葩尺寸。如此一来就决定了在制作H5的页面中rem并不适合用到段落文本上。所以在Flexible整个适配方案中考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。div{width:1rem;height:0.4rem;font-size:12px;// 默认写上dpr为1的fontSize}[data-dpr2] div{font-size:24px;}[data-dpr3] div{font-size:36px;}