使用Flexible实现手淘H5页面的终端适配
此段代码实现动态计算,事实上他做了这几样事情:
代码:
;(function(win,lib) { var doc = win.document; var docEl = doc.documentElement; var metaEl = doc.querySelector('meta[name="viewport"]'); var flexibleEl = doc.querySelector('meta[name="flexible"]'); var dpr = 0; var scale = 0; var tid; var flexible = lib.flexible || (lib.flexible = {}); if (metaEl) { console.warn('将根据已有的meta标签来设置缩放比例'); var match = metaEl.getAttribute('content').match(/initial-scale=([d.]+)/); if (match) { scale = parseFloat(match[1]); dpr = parseInt(1 / scale); } } else if (flexibleEl) { var content = flexibleEl.getAttribute('content'); if (content) { var initialDpr = content.match(/initial-dpr=([d.]+)/); var maximumDpr = content.match(/maximum-dpr=([d.]+)/); if (initialDpr) { dpr = parseFloat(initialDpr[1]); scale = parseFloat((1 / dpr).toFixed(2)); } if (maximumDpr) { dpr = parseFloat(maximumDpr[1]); scale = parseFloat((1 / dpr).toFixed(2)); } } } if (!dpr && !scale) { var isAndroid = win.navigator.appVersion.match(/android/gi); var isIPhone = win.navigator.appVersion.match(/iphone/gi); var devicePixelRatio = win.devicePixelRatio; if (isIPhone) { // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案 if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { // 其他设备下,仍旧使用1倍的方案 dpr = 1; } scale = 1 / dpr; } docEl.setAttribute('data-dpr',dpr); if (!metaEl) { metaEl = doc.createElement('meta'); metaEl.setAttribute('name','viewport'); metaEl.setAttribute('content','initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale + ',user-scalable=no'); if (docEl.firstElementChild) { docEl.firstElementChild.appendChild(metaEl); } else { var wrap = doc.createElement('div'); wrap.appendChild(metaEl); doc.write(wrap.innerHTML); } } function refreshRem(){ var width = docEl.getBoundingClientRect().width; // if (width / dpr > 540) { // width = 540 * dpr; // } var rem = width / 10; docEl.style.fontSize = rem + 'px'; flexible.rem = win.rem = rem; } win.addEventListener('resize',function() { clearTimeout(tid); tid = setTimeout(refreshRem,300); },false); win.addEventListener('pageshow',function(e) { if (e.persisted) { clearTimeout(tid); tid = setTimeout(refreshRem,300); } },false); win.addEventListener("orientationchange",function() { clearTimeout(timer); timer = setTimeout(setFontSize,false); if (doc.readyState === 'complete') { doc.body.style.fontSize = 12 * dpr + 'px'; } else { doc.addEventListener('DOMContentLoaded',function(e) { doc.body.style.fontSize = 12 * dpr + 'px'; },false); } refreshRem(); flexible.dpr = win.dpr = dpr; flexible.refreshRem = refreshRem; flexible.rem2px = function(d) { var val = parseFloat(d) * this.rem; if (typeof d === 'string' && d.match(/rem$/)) { val += 'px'; } return val; } flexible.px2rem = function(d) { var val = parseFloat(d) / this.rem; if (typeof d === 'string' && d.match(/px$/)) { val += 'rem'; } return val; } })(window,window['lib'] || (window['lib'] = {})); 曾几何时为了兼容IE低版本浏览器而头痛,以为到Mobile时代可以跟这些麻烦说拜拜。可没想到到了移动时代,为了处理各终端的适配而乱了手脚。对于混迹各社区的偶,时常发现大家拿手机淘宝的H5页面做讨论——手淘的H5页面是如何实现多终端的适配? 那么趁此Amfe阿里无线前端团队双11技术连载之际,用一个实战案例来告诉大家,手淘的H5页面是如何实现多终端适配的,希望这篇文章对大家在Mobile的世界中能过得更轻松。 目标拿一个双11的Mobile页面来做案例,比如你实现一个类似下图的一个H5页面:
目标很清晰,就是做一个这样的H5页面。 DEMO请用手机扫下面的二维码 痛点虽然H5的页面与PC的Web页面相比简单了不少,但让我们头痛的事情是要想尽办法让页面能适配众多不同的终端设备。看看下图你就会知道,这是多么痛苦的一件事情:
点击这里查看更多终端设备的参数。 再来看看手淘H5要适配的终端设备数据: 看到这些数据,是否死的心都有了,或者说为此捏了一把汗出来。 手淘团队适配协作模式早期移动端开发,对于终端设备适配问题只属于Android系列,只不过很多设计师常常忽略Android适配问题,只出一套iOS平台设计稿。但随着iPhone6,iPhone6+的出现,从此终端适配问题不再是Android系列了,也从这个时候让移动端适配全面进入到“杂屏”时代。 上图来自于paintcodeapp.com 为了应对这多么的终端设备,设计师和前端开发之间又应该采用什么协作模式?或许大家对此也非常感兴趣。 而整个手淘设计师和前端开发的适配协作基本思路是:
还是上一张图吧,因为一图胜过千言万语: 在此也不做更多的阐述。在手淘的设计师和前端开发协作过程中:手淘设计师常选择iPhone6作为基准设计尺寸,交付给前端的设计尺寸是按 根据上面所说的,设计师给我们的设计图是一个 前端开发完成终端适配方案拿到设计师给的设计图之后,剩下的事情是前端开发人员的事了。而手淘经过多年的摸索和实战,总结了一套移动端适配的方案——flexible方案。 这种方案具体在实际开发中如何使用,暂时先卖个关子,在继续详细的开发实施之前,我们要先了解一些基本概念。 一些基本概念在进行具体实战之前,首先得了解下面这些基本概念(术语): 视窗 viewport简单的理解,viewport是严格等于浏览器的窗口。在桌面浏览器中,viewport就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。 移动端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport:虚拟的viewportvisualviewport和布局的viewportlayoutviewport。 George Cummins在Stack Overflow上对这两个基本概念做了详细的解释。 而事实上viewport是一个很复杂的知识点,上面的简单描述可能无法帮助你更好的理解viewport,而你又想对此做更深的了解,可以阅读PPK写的相关教程。 物理像素(physical pixel)物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度。正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。 设备独立像素(density-independent pixel)设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。 CSS像素CSS像素是一个抽像的单位,主要使用在浏览器上,用来精确度量Web页面上的内容。一般情况之下,CSS像素称为与设备无关的像素(device-independent pixel),简称DIPs。 屏幕密度屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(PPI)。 设备像素比(device pixel ratio)设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到: 设备像素比 = 物理像素 / 设备独立像素 在JavaScript中,可以通过 dip或dp,(device independent pixels,设备独立像素)与屏幕密度有关。dip可以用来辅助区分视网膜设备还是非视网膜设备。 缩合上述的几个概念,用一张图来解释: 众所周知,iPhone6的设备宽度和高度为 如下图所示,某元素的CSS样式: width: 2px; height: 2px; 在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。在普通屏幕下 有关于更多的介绍可以点击这里详细了解。 看到这里,你能感觉到,在移动端时代屏幕适配除了Layout之外,还要考虑到图片的适配,因为其直接影响到页面显示质量,对于如何实现图片适配,再此不做过多详细阐述。这里盗用了@南宮瑞揚根据mir.aculo.us翻译的一张信息图: meta标签 <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
代码以显示网页的屏幕宽度定义了视窗宽度。网页的比例和最大比例被设置为100%。 留个悬念,因为后面的解决方案中需要重度依赖 CSS单位rem 在W3C规范中是这样描述
简单的理解, 前端实现方案 了解了前面一些相关概念之后,接下来我们来看实际解决方案。在整个手淘团队,我们有一个名叫 lib-flexible是什么?lib-flexible是一个制作H5适配的开源库,可以点击这里下载相关文件,获取需要的JavaScript和CSS文件。 当然你可以直接使用阿里CDN: script src="http://g.tbcdn.cn/mtb/lib-flexible/{{version}}/??flexible_css.js,flexible.js"></script> 将代码中的 使用方法lib-flexible库的使用方法非常的简单,只需要在Web页面的 第一种方法是将文件下载到你的项目中,然后通过相对路径添加: "build/flexible_css.debug.js"></script> <"build/flexible.debug.js"></ 或者直接加载阿里CDN的文件:"http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,sans-serif"> 另外强烈建议对JS做内联处理,在所有资源加载之前执行这个JS。执行这个JS后,会在 其中 if (!dpr && !scale) { var isAndroid = win.navigator.appVersion.match(/android/gi); var isIPhone = win.navigator.appVersion.match(/iphone/gi); var devicePixelRatio = win.devicePixelRatio; if (isIPhone) { // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案 if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { // 其他设备下,仍旧使用1倍的方案 dpr = 1; } scale = 1 / dpr; } flexible的实质flexible实际上就是能过JS来动态改写 var metaEl = doc.createElement('meta'); var scale = isRetina ? 0.5:1; metaEl.setAttribute('name','viewport'); metaEl.setAttribute('content',152)">'initial-scale=' + scale + ',maximum-scale=' + scale + if (docEl.firstElementChild) { document.documentElement.firstElementChild.appendChild(metaEl); } else { var wrap = doc.createElement('div'); wrap.appendChild(metaEl); documen.write(wrap.innerHTML); } 事实上他做了这几样事情:
案例实战了解Flexible相关的知识之后,咱们回到文章开头。我们的目标是制作一个适配各终端的H5页面。别的不多说,动手才能丰衣足食。 创建HTML模板<!DOCTYPE html> <html lang="en"> <head> <charset="utf-8"> <"yes" "apple-mobile-web-app-capable"> <"apple-touch-fullscreen"> <"telephone=no,email=no" "format-detection"> <script> <link rel="apple-touch-icon" href="favicon.png"> <"Shortcut Icon" "favicon.png" type="image/x-icon"> <title>再来一波</title> </head> <body> <!-- 页面结构写在这里 --> </body> </html> 正如前面所介绍的一样,首先加载了Flexible所需的配置: 这个时候可以根据设计的图需求,在HTML文档的 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |