1.思路
1)选择一种尺寸作为设计和开发基准
2)定义一套适配规则,自动适配剩下的两种尺寸,其实不止两种
3) 特殊适配效果给出
2.基本概念
1)物理像素
2)设备独立像素 dp 与屏幕密度有关,可以用来辅助区分是否是视网膜设备,
3)css像素 (DPIS) 抽象单位,使用在浏览器上,用来精确度量web页面内容。
4)屏幕密度 (PPI) 一个设备表面上存在的像素数量,以每英寸有多少像素来计算。
5)设备像素比 (dpr)物理像素 / 设备独立像素
-- window.devicePixelRatio 获取当前设备的dpr
-- -webkit-device-pixel-ratio, -webkit-min-device-pixel-ratio, -webkit-max-device-pixel-ratio 进行媒体查询,对不同的dpr做一些适配(只是webkit和webview)
示例:ip6的设备 宽高 375*667,可以理解为设备的独立像素。 它的dpr为2,物理像素为,750pt*1334pt;
某个元素css为
width:200px;height:200px;
不同屏幕上css像素所呈现的物理尺寸是一致的,而不同的是css像素所对应的物理像素不一致。
普通屏幕1个css像素对应1个物理像素
Retina屏幕1个css像素对应四个物理像素
6) viewport meta标签 之后重度依赖
7) rem
3. 具体方案
大概原理
-- 动态改写 meta 标签 --给html加上data-dpr属性,动态改写data-dpr的值 --给html增加font-size属性,动态改写font-size的值
1)库 lib-flexible
原理:在所有js执行之前加载这个js,会在html标签上增加一个data-dpr 属性,以及一个 font-size 样式,js会根据不同的设备添加不同的dpr,同时给html加上对应的font-size值,这样页面中的所有的元素都可以通过rem来设置,
注意:也可以通过 <meta name="flexible" content="initial-dpr=2" /> 来强制设置dpr,不建议
2)设置dpr的方案
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; }
3)动态改写meta标签
这里需要严重注意的是:
1.scale 设定为0.5是为了解决移动端的1px 在ratina屏幕的显示问题,可是它的bug 是会导致字体大小的怪异解析。
解决的办法是 自定义meta标签,设定initial-scale 的大小。这个库会判断若有meta标签不会覆盖你的设定。这样的话就不会在iphone里面的字体大小的怪异解析过程。
另一个比较有趣的现象是:在一个段落中汉字的阿拉伯数字比较多的时候会增加怪异解析的概率。具体原因不详。
以下代码大家只要知道原理即可。明白可以通过这样设定来解决 1px的问题。 实际应用时候,具体问题具体分析。
var metaEl = doc.createElement('meta');var scale = isRetina ? 0.5:1;metaEl.setAttribute('name', 'viewport');metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');if (docEl.firstElementChild) { document.documentElement.firstElementChild.appendChild(metaEl);} else { var wrap = doc.createElement('div'); wrap.appendChild(metaEl); documen.write(wrap.innerHTML); }