web移动端开发总结1--适配篇(2017.10.10)
aermin opened this issue · 2 comments
在公司主要写web移动端的项目,一开始较大的感触就是适配很麻烦,分ios和安卓,安卓生态又混乱得很,所以适配要做好了,不然这个设备好好的,有些设备却页面错乱。
在网上找了很多方案,踩了不少坑。
方案一:
(function (doc, win) {
console.log("dpr:"+win.devicePixelRatio);
var docEle = doc.documentElement,
isIos = navigator.userAgent.match(/iphone|ipod|ipad/gi),
dpr=Math.min(win.devicePixelRatio, 3);
scale = 1 / dpr,
resizeEvent = 'orientationchange' in window ? 'orientationchange' : 'resize';
docEle.dataset.dpr = dpr;
var metaEle = doc.createElement('meta');
metaEle.name = 'viewport';
metaEle.content = 'initial-scale=' + scale + ',maximum-scale=' + scale;
docEle.firstElementChild.appendChild(metaEle);
var recalCulate = function () {
var width = docEle.clientWidth;
if (width / dpr > 640) {
width = 640 * dpr;
}
docEle.style.fontSize = 20 * (width / 750) + 'px';
};
recalCulate()
if (!doc.addEventListener) return;
win.addEventListener(resizeEvent, recalCulate, false);
})(document, window);
获取设备dpr
算出缩放比例 scale = 1/dpr
创建meta以及属性
将scale值赋给initial-scale,maximum-scale
meta插入到文档中
创建屏幕大小改变重新计算函数并监听
特点:这个方案根据设备等比例缩放,每个设备显示内容一致。
缺点:当我用这套方案时,有个问题,因为监听resizeEvent,导致页面打开会先内容变大,然后再正常显示,很是影响用户体验。
参考链接
方案二(推荐):
//获取屏幕比例
function sreenRatio() {
const ua = navigator.userAgent;
const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i);
const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);
const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;
const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
var dpr = window.devicePixelRatio || 1;
if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {
// 如果非iOS, 非Android4.3以上, 非UC内核, 就不执行高清, dpr设为1;
dpr = 1;
}
return dpr;
}
//初始化屏幕比例
function screenRatio(baseFontSize, fontscale) {
var ratio = sreenRatio();
var scale = document.createElement('meta');
var scaleRatio = 1 / ratio;
scale.name = 'viewport';
scale.content = 'width=device-width,'+'initial-scale=' + scaleRatio + ', maximum-scale=' + scaleRatio + ', minimum-scale=' +
scaleRatio + ', user-scalable=no';
var s = document.getElementsByTagName('title')[0];
s.parentNode.insertBefore(scale, s);
var _baseFontSize = baseFontSize || 100;
var _fontscale = fontscale || 1;
document.documentElement.style.fontSize = _baseFontSize / 2 * ratio * _fontscale+'px';
}
if (window.screen.width >= 768) {
screenRatio(100, 1.5);//字体放大1.5倍
} else {
screenRatio();
}
特点:
- 引用简单,布局简便
- 根据设备屏幕的DPR,自动设置最合适的高清缩放。
- 保证了不同设备下视觉体验的一致性。(老方案是,屏幕越大元素越大;此方案是,屏幕越大,看的越多)
- 有效解决移动端真实1px问题(这里的1px 是设备屏幕上的物理像素)
ps:而且不会出现方案一的问题
缺点:1.有可能会出现字体会不受控制的变大的情况,解决方法:css加上一下内容
*, *:before, *:after { max-height: 100000px }
- 感觉没啥问题了,然而我司测试硬生生发现一个bug -> 在某安卓设备发现在QQ上打开网页出现页面错乱。解决方法:判断如果是安卓设备,scale.content加上target-densitydpi=device-dpi
修正:
//获取屏幕比例
function getDpr() {
const ua = navigator.userAgent;
const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i);
const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);
const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;
const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
var dpr = window.devicePixelRatio || 1;
if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {
// 如果非iOS, 非Android4.3以上, 非UC内核, 就不执行高清, dpr设为1;
dpr = 1;
}
return dpr;
}
//初始化屏幕比例
function screenRatio(baseFontSize, fontscale) {
var dpr = getDpr();
var scale = document.createElement('meta');
var scaleRatio = 1 / dpr;
scale.name = 'viewport';
<%/*安卓设备兼容*/%>
if (/Android/i.test(navigator.userAgent) == true) {
scale.content = 'width=device-width, target-densitydpi=device-dpi,'+' initial-scale=' + scaleRatio + ', maximum-scale=' + scaleRatio + ', minimum-scale=' +
scaleRatio + ', user-scalable=no';
<%/*iOS设备*/%>
} else {
scale.content = 'width=device-width,'+'initial-scale=' + scaleRatio + ', maximum-scale=' + scaleRatio + ', minimum-scale=' +
scaleRatio + ', user-scalable=no';
}
var s = document.getElementsByTagName('title')[0];
s.parentNode.insertBefore(scale, s);
var _baseFontSize = baseFontSize || 100;
var _fontscale = fontscale || 1;
document.documentElement.style.fontSize = _baseFontSize / 2 * dpr * _fontscale+'px';
}
var isAndroid = /Android/i.test(navigator.userAgent) ? true : false;
<%/*安卓设备不做高清放大处理*/%>
if (window.screen.width >= 768 && !isAndroid) {
screenRatio(null, 1.5);<%/*字体放大1.5倍*/%>
} else {
screenRatio();
}
知识点补充:
像素
实际上分为两种:设备像素和CSS像素
1、设备像素(device independent pixels): 设备屏幕的物理像素,任何设备的物理像素的数量都是固定的
2、CSS像素(CSS pixels): 是为web开发者创造的,在CSS和javascript中使用的一个抽象的层,每一个CSS声明和几乎所有的javascript属性都使用CSS像素,因此实际上从来用不上设备像素 ,唯一的例外是screen.width/height
DPR
设备像素比DPR(devicePixelRatio)是默认缩放为100%的情况下,设备像素和CSS像素的比值
DPR = 设备像素 / CSS像素(某一方向上)
以iphone5为例,iphone5的CSS像素为320px568px,DPR是2,所以其设备像素为640px1136px
- 由于DRP的存在,所以如果不做处理,会有1px线变粗问题,如果DPR为2,那css的1px起始到了设备像素中变了2px的视觉效果。
解决办法是viewport的initial-scale设置成1/dpr 在页面初始化时缩放成1/2,也就是css的1px变成0.5px,设备像素达到1px的视觉效果(你看到的)。
viewport
一个典型的针对移动端优化的站点包含类似下面的内容:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
width:控制 viewport 的大小,可以指定的一个值,如果 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
height:和 width 相对应,指定高度。
initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
maximum-scale:允许用户缩放到的最大比例。
minimum-scale:允许用户缩放到的最小比例。
user-scalable:用户是否可以手动缩放。
推荐使用postcss里面的插件,或者webpack 的px2rem ,会根据屏幕尺寸自动计算换算rem。一站式解决方案。