所谓前端适配,就是为了让移动设计稿在大部分的移动设备上看起来有一致的展示效果,目前比较流行的方法有两种。各有利弊,使用第一种在某些浏览器的webview里面会出现兼容问题,而且对于1像素会无法渲染。而用rem的方案在背景和字体上也会有某些问题。
方案一:强制meta viewport的宽度为设计稿的宽度
把下面的代码放在头部,然后制作稿跟PC上一样的制作就行
// 根据设计稿的宽度来传参 比如640 750 1125
!function(designWidth){
if (/Android(?:\s+|\/)(\d+\.\d+)?/.test(navigator.userAgent)) {
var version = parseFloat(RegExp.$1);
if (version > 2.3) {
var phoneScale = parseInt(window.screen.width) / designWidth;
document.write('<meta name="viewport" content="width=' + designWidth + ',minimum-scale=' + phoneScale + ',maximum-scale=' + phoneScale + ', target-densitydpi=device-dpi">');
} else {
document.write('<meta name="viewport" content="width=' + designWidth + ',target-densitydpi=device-dpi">');
}
} else {
document.write('<meta name="viewport" content="width=' + designWidth + ',user-scalable=no,target-densitydpi=device-dpi,minimal-ui,viewport-fit=cover">');
}
}(640);
方案2:使用淘宝的rem精简版
//计算尺寸时,只需要将对应的尺寸除以100。
源码:
(function(designWidth, maxWidth) {
var doc = document,
win = window;
var docEl = doc.documentElement;
var metaEl,
metaElCon;
var styleText,
remStyle = document.createElement("style");
var tid;
function refreshRem() {
// var width = parseInt(window.screen.width); // uc有bug
var width = docEl.getBoundingClientRect().width;
if (!maxWidth) {
maxWidth = 540;
};
if (width > maxWidth) { // 淘宝做法:限制在540的屏幕下,这样100%就跟10rem不一样了
width = maxWidth;
}
var rem = width * 100 / designWidth;
// var rem = width / 10; // 如果要兼容vw的话分成10份 淘宝做法
//docEl.style.fontSize = rem + "px"; //旧的做法,在uc浏览器下面会有切换横竖屏时定义了font-size的标签不起作用的bug
remStyle.innerHTML = 'html{font-size:' + rem + 'px;}';
}
// 设置 viewport ,有的话修改 没有的话设置
metaEl = doc.querySelector('meta[name="viewport"]');
// 20171219修改:增加 viewport-fit=cover ,用于适配iphoneX
metaElCon = "width=device-width,initial-scale=1,maximum-scale=1.0,user-scalable=no,viewport-fit=cover";
if(metaEl) {
metaEl.setAttribute("content", metaElCon);
}else{
metaEl = doc.createElement("meta");
metaEl.setAttribute("name", "viewport");
metaEl.setAttribute("content", metaElCon);
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
}else{
var wrap = doc.createElement("div");
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
wrap = null;
}
}
//要等 wiewport 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
refreshRem();
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(remStyle);
} else {
var wrap = doc.createElement("div");
wrap.appendChild(remStyle);
doc.write(wrap.innerHTML);
wrap = null;
}
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);
if (doc.readyState === "complete") {
doc.body.style.fontSize = "16px";
} else {
doc.addEventListener("DOMContentLoaded", function(e) {
doc.body.style.fontSize = "16px";
}, false);
}
})(750, 750);