移动端(手机端)页面自适应解决方案—rem布局
作者:互联网
移动端(手机端)页面自适应解决方案—rem布局
假设设计妹妹给我们的设计稿尺寸为750 * 1340。结合网易、淘宝移动端首页html元素上的动态font-size属性、设计稿尺寸、前端与设计之间协作流程一般分为下面两种:
一、网易做法:
引入:页面开头处引入下面这段代码,用于动态计算font-size
(function(doc, win) {
var docEl = doc.documentElement,
isIOS = navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),
dpr = isIOS ? Math.min(win.devicePixelRatio, 3) : 1,
dpr = window.top === window.self ? dpr : 1, //被iframe引用时,禁止缩放
dpr = 1,
scale = 1 / dpr,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
docEl.dataset.dpr = dpr;
var metaEl = doc.createElement('meta');
metaEl.name = 'viewport';
metaEl.content = 'initial-scale=' + scale + ',maximum-scale=' + scale + ', minimum-scale=' + scale;
docEl.firstElementChild.appendChild(metaEl);
var recalc = function() {
var width = docEl.clientWidth;
if (width / dpr > 750) {
width = 750 * dpr;
}
// 乘以100,px : rem = 100 : 1
docEl.style.fontSize = 100 * (width / 750) + 'px';
};
recalc()
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
})(document, window);
使用:
未引入前:
body {
width: 750px;
height: 640px;
}
引入后:除以100并将px换成rem
body {
width: 7.5rem;
height: 6.4rem;
}
换算的依据:
// 乘以100,px : rem = 100 : 1
var recalc = function() {
var width = docEl.clientWidth;
if (width / dpr > 750) {
width = 750 * dpr;
}
// 乘以100,px : rem = 100 : 1
docEl.style.fontSize = 100 * (width / 750) + 'px';
};
二、淘宝做法(推荐做法,尤其是app内嵌页面):
引入:页面开头处引入下面这段代码,用于动态计算font-size,或者单独放入一个文件,引入文件也可以
})(window, window[‘lib’] || (window[‘lib’] = {}));" title="" data-original-title=“已复制”>
;
(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 (<span class="hljs-name">metaEl</span>) {
var match = metaEl.getAttribute(<span class="hljs-name">'content'</span>).match(/initial\-scale=([\d\.]+)/)<span class="hljs-comment">;</span>
if (<span class="hljs-name">match</span>) {
scale = parseFloat(<span class="hljs-name">match</span>[<span class="hljs-number">1</span>])<span class="hljs-comment">;</span>
dpr = parseInt(<span class="hljs-number">1</span> / scale)<span class="hljs-comment">;</span>
}
} else if (<span class="hljs-name">flexibleEl</span>) {
var content = flexibleEl.getAttribute(<span class="hljs-name">'content'</span>)<span class="hljs-comment">;</span>
if (<span class="hljs-name">content</span>) {
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/)<span class="hljs-comment">;</span>
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/)<span class="hljs-comment">;</span>
if (<span class="hljs-name">initialDpr</span>) {
dpr = parseFloat(<span class="hljs-name">initialDpr</span>[<span class="hljs-number">1</span>])<span class="hljs-comment">;</span>
scale = parseFloat((<span class="hljs-number">1</span> / dpr).toFixed(<span class="hljs-number">2</span>))<span class="hljs-comment">;</span>
}
if (<span class="hljs-name">maximumDpr</span>) {
dpr = parseFloat(<span class="hljs-name">maximumDpr</span>[<span class="hljs-number">1</span>])<span class="hljs-comment">;</span>
scale = parseFloat((<span class="hljs-number">1</span> / dpr).toFixed(<span class="hljs-number">2</span>))<span class="hljs-comment">;</span>
}
}
}
if (<span class="hljs-name">!dpr</span> && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi)<span class="hljs-comment">;</span>
var isIPhone = win.navigator.appVersion.match(/iphone/gi)<span class="hljs-comment">;</span>
var devicePixelRatio = win.devicePixelRatio;
if (<span class="hljs-name">isIPhone</span>) {
// iOS下,对于<span class="hljs-number">2</span>和<span class="hljs-number">3</span>的屏,用<span class="hljs-number">2</span>倍的方案,其余的用<span class="hljs-number">1</span>倍方案
if (<span class="hljs-name">devicePixelRatio</span> >= <span class="hljs-number">3</span> && (<span class="hljs-name">!dpr</span> || dpr >= <span class="hljs-number">3</span>)) {
dpr = <span class="hljs-number">3</span><span class="hljs-comment">;</span>
} else if (<span class="hljs-name">devicePixelRatio</span> >= <span class="hljs-number">2</span> && (<span class="hljs-name">!dpr</span> || dpr >= <span class="hljs-number">2</span>)) {
dpr = <span class="hljs-number">2</span><span class="hljs-comment">;</span>
} else {
dpr = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
}
} else {
// 其他设备下,仍旧使用<span class="hljs-number">1</span>倍的方案
dpr = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
}
scale = <span class="hljs-number">1</span> / dpr;
}
docEl.setAttribute(<span class="hljs-name">'data-dpr'</span>, dpr)<span class="hljs-comment">;</span>
if (<span class="hljs-name">!metaEl</span>) {
metaEl = doc.createElement(<span class="hljs-name">'meta'</span>)<span class="hljs-comment">;</span>
metaEl.setAttribute(<span class="hljs-name">'name'</span>, 'viewport')<span class="hljs-comment">;</span>
metaEl.setAttribute(<span class="hljs-name">'content'</span>, 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no')<span class="hljs-comment">;</span>
if (<span class="hljs-name">docEl.firstElementChild</span>) {
docEl.firstElementChild.appendChild(<span class="hljs-name">metaEl</span>)<span class="hljs-comment">;</span>
} else {
var wrap = doc.createElement(<span class="hljs-name">'div'</span>)<span class="hljs-comment">;</span>
wrap.appendChild(<span class="hljs-name">metaEl</span>)<span class="hljs-comment">;</span>
doc.write(<span class="hljs-name">wrap.innerHTML</span>)<span class="hljs-comment">;</span>
}
}
function refreshRem() {
var width = docEl.getBoundingClientRect().width;
// 适配平板
if (<span class="hljs-name">width</span> / dpr > <span class="hljs-number">540</span>) {
width = <span class="hljs-number">540</span> * dpr;
}
var rem = width / <span class="hljs-number">10</span><span class="hljs-comment">;</span>
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
win.addEventListener(<span class="hljs-name">'resize'</span>, function() {
clearTimeout(<span class="hljs-name">tid</span>)<span class="hljs-comment">;</span>
tid = setTimeout(<span class="hljs-name">refreshRem</span>, <span class="hljs-number">300</span>)<span class="hljs-comment">;</span>
}, <span class="hljs-literal">false</span>)<span class="hljs-comment">;</span>
win.addEventListener(<span class="hljs-name">'pageshow'</span>, function(<span class="hljs-name">e</span>) {
if (<span class="hljs-name">e.persisted</span>) {
clearTimeout(<span class="hljs-name">tid</span>)<span class="hljs-comment">;</span>
tid = setTimeout(<span class="hljs-name">refreshRem</span>, <span class="hljs-number">300</span>)<span class="hljs-comment">;</span>
}
}, <span class="hljs-literal">false</span>)<span class="hljs-comment">;</span>
if (<span class="hljs-name">doc.readyState</span> === 'complete') {
doc.body.style.fontSize = <span class="hljs-number">12</span> * dpr + 'px';
} else {
doc.addEventListener(<span class="hljs-name">'DOMContentLoaded'</span>, function(<span class="hljs-name">e</span>) {
doc.body.style.fontSize = <span class="hljs-number">12</span> * dpr + 'px';
}, <span class="hljs-literal">false</span>)<span class="hljs-comment">;</span>
}
refreshRem()<span class="hljs-comment">;</span>
flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
flexible.rem2px = function(<span class="hljs-name">d</span>) {
var val = parseFloat(<span class="hljs-name">d</span>) * this.rem;
if (<span class="hljs-name">typeof</span> d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(<span class="hljs-name">d</span>) {
var val = parseFloat(<span class="hljs-name">d</span>) / this.rem;
if (<span class="hljs-name">typeof</span> d === 'string' && d.match(/px$/)) {
val += 'rem';
}
return val;
}
})(window, window[‘lib’] || (window[‘lib’] = {}));
使用:
未引入前:
body {
width: 750px;
height: 640px;
}
引入后:
@font-size-base: 75;
body {
width: 750rem/@font-size-base;
height: 640rem/@font-size-base;
}
换算依据:
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;
}
这边是用的less,如果您没有用less,就需要手动计算,当然也可以转化为px : rem = 100 : 1。
如果想转化为px : rem = 100 : 1,可以修改上面的refreshRem函数:
function refreshRem() {
var width = docEl.getBoundingClientRect().width
// 适配平板
if (width / dpr > 750) {
width = 750 * dpr
}
var rem = 100 * (width / 750)
docEl.style.fontSize = rem + 'px'
flexible.rem = win.rem = rem;
}
使用:
未引入前:
body {
width: 750px;
height: 640px;
}
引入后:除以100并将px换成rem
body {
width: 7.5rem;
height: 6.4rem;
}
换算依据就是上面修改的代码:
function refreshRem() {
var width = docEl.getBoundingClientRect().width
// 适配平板
if (width / dpr > 750) {
width = 750 * dpr
}
var rem = 100 * (width / 750)
docEl.style.fontSize = rem + 'px'
flexible.rem = win.rem = rem;
}
具体实现原理请参照:从网易与淘宝的font-size思考前端设计稿与工作流,写的很不错!
希望对需要的朋友有所帮助!
标签:docEl,scale,dpr,解决方案,width,rem,var,页面 来源: https://blog.csdn.net/weixin_43844392/article/details/89880009