移动端适配 野性酷女 2022-01-25 18:23 444阅读 0赞 在上一片文章里,关于如何使用rem进行布局,我作了一个大概的描述。 今天这篇文字,主要说一个东西-dpr。 我们都知道,移动端开发,运行的平台主要是 ios 和 android ,做适配的时候,也会对不同的屏幕做一些特别的处理。 首先,先看一下这两家的屏幕吧。 ![Image 1][] 设备概况 眼花缭乱是不是,不要紧,我们只看我们需要的信息。 废话不多说,直接上结论: IOS的移动设备: iPhone4, 4s, 5, 5s, 6, 6+, 6s, 6s+ 都是Retina屏, 其中4, 4s, 5, 5s, 6, 6s的ppi都是326,dpr都是2,6+和6s+ppi是441,dpr是3。在ipad上同样只有dpr2和3两种的屏幕。 <table> <thead> <tr> <th>IOS设备</th> <th>PPI</th> <th>DPR</th> </tr> </thead> <tbody> <tr> <td>iPhone4</td> <td>326</td> <td>2</td> </tr> <tr> <td>iPhone4s</td> <td>326</td> <td>2</td> </tr> <tr> <td>iPhone5</td> <td>326</td> <td>2</td> </tr> <tr> <td>iPhone5s</td> <td>326</td> <td>2</td> </tr> <tr> <td>iPhone6</td> <td>326</td> <td>2</td> </tr> <tr> <td>iPhone6s</td> <td>326</td> <td>2</td> </tr> <tr> <td>iPhone6 PLUS</td> <td>441</td> <td>3</td> </tr> <tr> <td>iPhone6s PLUS</td> <td>441</td> <td>3</td> </tr> <tr> <td>iPad -</td> <td>-</td> <td>2</td> </tr> <tr> <td>iPad -</td> <td>-</td> <td>3</td> </tr> </tbody> </table> 总的来说,ios设备的dpr总体来说比较一致。 再看看安卓: <table> <thead> <tr> <th>android</th> <th>尺寸</th> <th>dpr</th> </tr> </thead> <tbody> <tr> <td>低清设备</td> <td>-</td> <td>1</td> </tr> <tr> <td>-</td> <td>-</td> <td>1.5</td> </tr> <tr> <td>-</td> <td>-</td> <td>1.75</td> </tr> <tr> <td>-</td> <td>-</td> <td>2</td> </tr> <tr> <td>mx2</td> <td>800*1280</td> <td>2.5</td> </tr> <tr> <td>小米note</td> <td>720*1280</td> <td>2.75</td> </tr> <tr> <td>-</td> <td>-</td> <td>3</td> </tr> <tr> <td>三星note4</td> <td>-</td> <td>4</td> </tr> <tr> <td>...</td> <td>...</td> <td>...</td> </tr> </tbody> </table> ![Image 1][] 卒 上一篇的末尾,提到了淘宝的移动端布局方案 Flexible. 源码如下: //去除了头部css部分 <pre> ! function(a, b) \{ function c() \{ var b = f.getBoundingClientRect().width; b / i > 540 && (b = 540 \* i); var c = b / 10; f.style.fontSize = c + "px", k.rem = a.rem = c \} var d, e = a.document, f = e.documentElement, g = e.querySelector('meta\[name="viewport"\]'), h = e.querySelector('meta\[name="flexible"\]'), i = 0, j = 0, k = b.flexible || (b.flexible = \{\}); if (g) \{ console.warn("将根据已有的meta标签来设置缩放比例"); var l = g.getAttribute("content").match(/initial-scale=(\[\\d.\]+)/); l && (j = parseFloat(l\[1\]), i = parseInt(1 / j)) \} else if (h) \{ var m = h.getAttribute("content"); if (m) \{ var n = m.match(/initial-dpr=(\[\\d.\]+)/), o = m.match(/maximum-dpr=(\[\\d.\]+)/); n && (i = parseFloat(n\[1\]), j = parseFloat((1 / i).toFixed(2))), o && (i = parseFloat(o\[1\]), j = parseFloat((1 / i).toFixed(2))) \} \} if (!i && !j) \{ var p = (a.navigator.appVersion.match(/android/gi), a.navigator.appVersion.match(/iphone/gi)), q = a.devicePixelRatio; i = p ? q >= 3 && (!i || i >= 3) ? 3 : q >= 2 && (!i || i >= 2) ? 2 : 1 : 1, j = 1 / i \} if (f.setAttribute("data-dpr", i), !g) if (g = e.createElement("meta"), g.setAttribute("name", "viewport"), g.setAttribute("content", "initial-scale=" + j + ", maximum-scale=" + j + ", minimum-scale=" + j + ", user-scalable=no"), f.firstElementChild) f.firstElementChild.appendChild(g); else \{ var r = e.createElement("div"); r.appendChild(g), e.write(r.innerHTML) \} a.addEventListener("resize", function() \{ clearTimeout(d), d = setTimeout(c, 300) \}, !1), a.addEventListener("pageshow", function(a) \{ a.persisted && (clearTimeout(d), d = setTimeout(c, 300)) \}, !1), "complete" === e.readyState ? e.body.style.fontSize = 12 \* i + "px" : e.addEventListener("DOMContentLoaded", function() \{ e.body.style.fontSize = 12 \* i + "px" \}, !1), c(), k.dpr = a.dpr = i, k.refreshRem = c, k.rem2px = function(a) \{ var b = parseFloat(a) \* this.rem; return "string" == typeof a && a.match(/rem$/) && (b += "px"), b \}, k.px2rem = function(a) \{ var b = parseFloat(a) / this.rem; return "string" == typeof a && a.match(/px$/) && (b += "rem"), b \} \}(window, window.lib || (window.lib = \{\})); </pre> ![Image 1][] 很显然,这是经过混淆的代码。 > 经过一番挣扎,成功实现肉身还原。 核心方法如下: <pre> if (metaEl) \{ console.warn('将根据已有的meta标签来设置缩放比例'); var match = metaEl.getAttribute('content').match(/initial-scale=(\[\\d.\]+)/); if (match) \{ scale = parseFloat(match\[1\]); dpr = parseInt(1 / scale); \} //如果在meta标签中,我们手动配置了flexible,则使用里面的内容 \} 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)); \} \} \} </pre> <pre> if (!dpr && !scale) \{ var isAndroid = window.navigator.appVersion.match(/android/gi); var isIPhone = window.navigator.appVersion.match(/iphone/gi); //devicePixelRatio这个属性是可以获取到设备的dpr的 var devicePixelRatio = window.devicePixelRatio; if (isIPhone) \{ if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) \{ dpr = 3; \} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2))\{ dpr = 2; \} else \{ dpr = 1; \} \} else \{ dpr = 1; // 其他设备仍旧使用1倍的方案 \} scale = 1 / dpr; \} </pre> 显而易见,这里只对ios作了处理,android 仍采用了1倍的布局方案。 个人觉得,android手机屏幕大小,宽高比是花开满地,要做的调整真的是太多了。如果根元素的font-size尺寸不对,页面效果不用多说。 就算把当前的设备信息都考虑进去了,那以后呢。 所以,考虑开发,维护,兼容性...淘宝这么做还是有道理的。 恩,也有看另一种方案,hotcss.js [http://imochen.github.io/hotcss/][http_imochen.github.io_hotcss] <pre> (function(window, document) \{ 'use strict'; //给hotcss开辟个命名空间,别问我为什么,我要给你准备你会用到的方法,免得用到的时候还要自己写。 var hotcss = {}; (function() { //根据devicePixelRatio自定计算scale //可以有效解决移动端1px这个世纪难题。 var viewportEl = document.querySelector('meta[name="viewport"]'), hotcssEl = document.querySelector('meta[name="hotcss"]'), dpr = window.devicePixelRatio || 1, maxWidth = 540, designWidth = 0; dpr = dpr >= 3 ? 3 : (dpr >= 2 ? 2 : 1); //允许通过自定义name为hotcss的meta头,通过initial-dpr来强制定义页面缩放 if (hotcssEl) { var hotcssCon = hotcssEl.getAttribute('content'); if (hotcssCon) { var initialDprMatch = hotcssCon.match(/initial\-dpr=([\d\.]+)/); if (initialDprMatch) { dpr = parseFloat(initialDprMatch[1]); } var maxWidthMatch = hotcssCon.match(/max\-width=([\d\.]+)/); if (maxWidthMatch) { maxWidth = parseFloat(maxWidthMatch[1]); } var designWidthMatch = hotcssCon.match(/design\-width=([\d\.]+)/); if (designWidthMatch) { designWidth = parseFloat(designWidthMatch[1]); } } } document.documentElement.setAttribute('data-dpr', dpr); hotcss.dpr = dpr; document.documentElement.setAttribute('max-width', maxWidth); hotcss.maxWidth = maxWidth; if (designWidth) { document.documentElement.setAttribute('design-width', designWidth); hotcss.designWidth = designWidth; } var scale = 1 / dpr, content = 'width=device-width, initial-scale=' + scale + ', minimum-scale=' + scale + ', maximum-scale=' + scale + ', user-scalable=no'; if (viewportEl) { viewportEl.setAttribute('content', content); } else { viewportEl = document.createElement('meta'); viewportEl.setAttribute('name', 'viewport'); viewportEl.setAttribute('content', content); document.head.appendChild(viewportEl); } })(); hotcss.px2rem = function(px, designWidth) { //预判你将会在JS中用到尺寸,特提供一个方法助你在JS中将px转为rem。就是这么贴心。 if (!designWidth) { //如果你在JS中大量用到此方法,建议直接定义 hotcss.designWidth 来定义设计图尺寸; //否则可以在第二个参数告诉我你的设计图是多大。 designWidth = parseInt(hotcss.designWidth, 10); } return parseInt(px, 10) * 320 / designWidth / 20; } hotcss.rem2px = function(rem, designWidth) { //新增一个rem2px的方法。用法和px2rem一致。 if (!designWidth) { designWidth = parseInt(hotcss.designWidth, 10); } //rem可能为小数,这里不再做处理了 return rem * 20 * designWidth / 320; } hotcss.mresize = function() { //对,这个就是核心方法了,给HTML设置font-size。 var innerWidth = document.documentElement.getBoundingClientRect().width || window.innerWidth; if (hotcss.maxWidth && (innerWidth / hotcss.dpr > hotcss.maxWidth)) { innerWidth = hotcss.maxWidth * hotcss.dpr; } if (!innerWidth) { return false; } document.documentElement.style.fontSize = (innerWidth * 20 / 320) + 'px'; hotcss.callback && hotcss.callback(); }; hotcss.mresize(); //直接调用一次 window.addEventListener('resize', function() { clearTimeout(hotcss.tid); hotcss.tid = setTimeout(hotcss.mresize, 33); }, false); //绑定resize的时候调用 window.addEventListener('load', hotcss.mresize, false); //防止不明原因的bug。load之后再调用一次。 setTimeout(function() { hotcss.mresize(); //防止某些机型怪异现象,异步再调用一次 }, 333) window.hotcss = hotcss; //命名空间暴露给你,控制权交给你,想怎么调怎么调。 \})(window, document); </pre> 里面有这样的设置: > dpr = dpr >= 3 ? 3 : ( dpr >=2 ? 2 : 1 ); 简单粗暴。 说到这里,说一下问题,也是我转去看flexible 代码的原因。 现在做的项目,使用的是hotcss , 然后出现了一个神奇的问题。 我的设备是iPhone5S ,系统版本8.3,微信版本6.3.15. 之前是6.3.13,更新到6.3.15之后,页面中的字体渲染完成之后,立刻会变大。刚开始怀疑是这些resize 的原因,断点调试,无果。 和腾讯的师兄说了一下,他并没有遇到这种情况。 然后,无意中发现,在微信字体设置中,改动一下字体,这种情况就没有了,恩,是在我的手机上没有了,在另一个同事的5s上依然有字体闪烁的情况。 我新建了一个分支,用上了flexible,表现良好,暂时没发现啥什么问题。 -------------------- 最后,附上我还原后的Flexible 源码, 有兴趣的小伙伴可以看看,希望能有所帮助。。 <pre> /\*\* * Created by kk on 16/3/28. */ /* hotcss 可能有神奇的问题 * \*/ !function() \{ var innerStyle = "@charset "utf-8";html\{color:\#000;background:\#fff;overflow-y:scroll;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%\}html \*\{outline:0;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)\}html,body\{font-family:sans-serif\}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section\{margin:0;padding:0\}input,select,textarea\{font-size:100%\}table\{border-collapse:collapse;border-spacing:0\}fieldset,img\{border:0\}abbr,acronym\{border:0;font-variant:normal\}del\{text-decoration:line-through\}address,caption,cite,code,dfn,em,th,var\{font-style:normal;font-weight:500\}ol,ul\{list-style:none\}caption,th\{text-align:left\}h1,h2,h3,h4,h5,h6\{font-size:100%;font-weight:500\}q:before,q:after\{content:''\}sub,sup\{font-size:75%;line-height:0;position:relative;vertical-align:baseline\}sup\{ [top:-.5em][top_-.5em]\}sub\{ [bottom:-.25em][bottom_-.25em]\}a:hover\{text-decoration:underline\}ins,a\{text-decoration:none\}", createStyle = document.createElement("style"); if (document.getElementsByTagName("head")\[0\].appendChild(createStyle), createStyle.styleSheet) createStyle.styleSheet.disabled || (createStyle.styleSheet.cssText = innerStyle); else try \{ createStyle.innerHTML = innerStyle; \} catch (ex) \{ createStyle.innerText = innerStyle; \} \}(); ! function(window, nameSpace) \{ var timer, doc = window.document, docEl = doc.documentElement, metaEl = doc.querySelector('meta\[name="viewport"\]'), flexibleEl = doc.querySelector('meta\[name="flexible"\]'), dpr = 0, scale = 0, Flexible = nameSpace.flexible || (nameSpace.flexible = \{\}); // 给Flexible 开创命名空间 //刷新rem function refreshRem() \{ var width = docEl.getBoundingClientRect().width; //width / dpr > 540 && (width = 540 * dpr); if(width / dpr > 540) { width = 540 * dpr ; } var rootSize = width / 10; docEl.style.fontSize = rootSize + "px", Flexible.rem = window.rem = rootSize; } if (metaEl) { console.warn('将根据已有的meta标签来设置缩放比例'); var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/); if (match) { scale = parseFloat(match[1]); dpr = parseInt(1 / scale); } //如果在meta标签中,我们手动配置了flexible,则使用里面的内容 } 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 = window.navigator.appVersion.match(/android/gi); var isIPhone = window.navigator.appVersion.match(/iphone/gi); //devicePixelRatio这个属性是可以获取到设备的dpr的 var devicePixelRatio = window.devicePixelRatio; if (isIPhone) { if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { dpr = 1; } scale = 1 / dpr; } if (docEl.setAttribute("data-dpr", dpr), !metaEl) if (metaEl = doc.createElement("meta"), metaEl.setAttribute("name", "viewport"), //j = scale //j = scale //j = scale metaEl.setAttribute("content", "initial-scale=" + scale + ", maximum-scale=" + scale + ", minimum-scale=" + scale + ", user-scalable=no"), docEl.firstElementChild) docEl.firstElementChild.appendChild(metaEl); else { var createDiv = doc.createElement("div"); createDiv.appendChild(metaEl), doc.write(createDiv.innerHTML) } window.addEventListener("resize", function() { clearTimeout(timer), timer = setTimeout(refreshRem, 300); }, !1), window.addEventListener("pageshow", function(a) { a.persisted && (clearTimeout(timer), timer = setTimeout(refreshRem, 300)) }, !1), "complete" === doc.readyState ? doc.body.style.fontSize = 17 * dpr + "px" : doc.addEventListener("DOMContentLoaded", function() { doc.body.style.fontSize = 17 * dpr + "px" }, !1), refreshRem(), Flexible.dpr = window.dpr = dpr, Flexible.refreshRem = refreshRem, Flexible.rem2px = function(a) { var pxValue = parseFloat(a) * this.rem; return "string" == typeof a && a.match(/rem$/) && (pxValue += "px"), pxValue ; }, Flexible.px2rem = function(a) { var remValue = parseFloat(a) / this.rem; return "string" == typeof a && a.match(/px$/) && (remValue += "rem"), remValue ; } \}(window, window.lib || (window.lib = \{\})); </pre> 运行截图: ![Image 1][] 运行截图 -------------------- 亲测无误,希望能给大家带来一点帮助,谢谢。 作者:Scaukk 转自:https://www.jianshu.com/p/221bebfae266 来源:简书 [Image 1]: [http_imochen.github.io_hotcss]: https://link.jianshu.com?t=http://imochen.github.io/hotcss/ [top_-.5em]: https://link.jianshu.com?t=top:-.5em [bottom_-.25em]: https://link.jianshu.com?t=bottom:-.25em
相关 vue移动端适配 如果不想转化成rem单位,可以把px写成大写的PX,就可以是px单位了哦 1、安装插件 npm i lib-flexible --save // 载l £神魔★判官ぃ/ 2022年12月20日 15:59/ 0 赞/ 204 阅读
相关 移动端适配模板 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> < 今天药忘吃喽~/ 2022年12月13日 15:29/ 0 赞/ 171 阅读
相关 移动端适配 rem计算JS方式 计算尺寸参照的标准尺寸 750px 换算比例为 100:1 (100px=1rem 50px=0.5rem 5px=0.05rem) Bertha 。/ 2022年10月19日 05:39/ 0 赞/ 367 阅读
相关 移动端适配 移动端适配 一、移动端适配是什么? 二、基本概念 1.移动端设备视口 2. 什么是rem? 三、解决方案 1. 调 客官°小女子只卖身不卖艺/ 2022年08月31日 01:46/ 0 赞/ 400 阅读
相关 移动端适配 转自:/images/20220528/a9ac319170c44a5d85b86b4f83df39bf.png 大多都是介绍手淘团队的[flexible.js][ 怼烎@/ 2022年05月27日 23:28/ 0 赞/ 405 阅读
相关 移动端 - 适配方案 1. 百分比适配 2. viewport 适配 3. rem 适配 4. 弹性盒模型 box flex 补充 ╰+攻爆jí腚メ/ 2022年05月26日 10:10/ 0 赞/ 287 阅读
相关 移动端适配 1、首先在html页面中引入meta标签 <meta name="viewport" content="width=device-width, initial-sc 水深无声/ 2022年03月17日 06:14/ 0 赞/ 360 阅读
相关 UEditor适配移动端 一.全局内容设置 使用getContent()接口,获取编辑器里的内容的HTML文档,用下面的格式去包裹,可以得到一个内容居中,屏幕两边留有一定边距,禁用缩放的页面 电玩女神/ 2022年03月12日 12:56/ 0 赞/ 545 阅读
相关 移动端适配 移动端适配 1、html <meta name="viewport" content="width=device-width,initial-scale=1.0 冷不防/ 2022年01月29日 03:13/ 0 赞/ 439 阅读
相关 移动端适配 在上一片文章里,关于如何使用rem进行布局,我作了一个大概的描述。 今天这篇文字,主要说一个东西-dpr。 我们都知道,移动端开发,运行的平台主要是 ios 和 andr 野性酷女/ 2022年01月25日 18:23/ 0 赞/ 445 阅读
还没有评论,来说两句吧...