HTML5移动端⾃适应解决⽅案
⾃接触移动端H5页⾯以来,从未停⽌对H5页⾯适配不同屏幕的解决⽅案的探索。从最初的bootstrap响应式框架来做⼿机适配;后来尝试⽤百分⽐去做H5的适配;接着⼜去尝试媒体查询,但移动端的屏幕⼤⼩个各异,各种尺⼨的机型都有,难以做到不同⼿机适配,后来看到京东,⽹易,⼿淘等使⽤rem做⼿机适配,使⽤rem前端开发者可以很⽅便的在各种屏幕尺⼨下,做出设计图要求的效果。本⽂重在说明⼿机端不同的⾃适应解决⽅案的优缺点以及rem作为主流的移动端⾃适应布局⽅案的原理以及使⽤⽅案。
1. 使⽤rem做⼿机适配
什么是rem
rem是css3新增的相对长度单位,是指相对于根元素html的font-size值的⼤⼩
扩展: em也是css的相对长度单位,em作为font-size的单位时,其代表⽗元素的字体⼤⼩,em作为其他属性单位时,代表⾃⾝字体⼤⼩
rem适配原理
rem布局适配的本质是等⽐缩放,根据不同屏幕的宽度,以相同的⽐例动态修改html的font-size值,它跟设
计师给出的设计图的⼤⼩没有关系,不管设计图给出的是480,720,750,1080,都是将设计稿等⽐缩放在设备上;那么根html的font-size的值是怎么计算的呢?
⽹易的⽅案是根据屏幕宽度与设计图宽度的⽐值作为font-size ⼤⼩,但此时计算出的font-size值⼩于12px会造成⼀些错误和奇怪的问题,为此我们把⽐例扩⼤100倍,即,根html的font-size值=屏幕宽度/设计图宽度*100 为了使⽐例不变,相应的设计图元素在变为rem 的过程中要除以100;
阿⾥的⽅案是根据设备像素⽐设置scale的值,保持视⼝device-width始终等于设备物理像素,接着根据屏幕宽度/10动态计算根html的font-size的⼤⼩,设计稿的像素单位如何换成以rem为单位呢?可以⽤⼀个⽐例来计算,具体是将设计图分成100份,每⼀份的宽度⽤a 来表⽰,同时认定1rem单位为10a,即1rem=10a;如设计稿宽度为750px,此时:
750px=100a --- 1a=7.5px
1rem=10a --- 1rem=75px
同理,如果设计稿总宽度是640px,则1rem=64px。
rem适配使⽤⽅案
(function(doc, win) {html手机网站
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function() {
var clientWidth = docEl.clientWidth;
if(!clientWidth) return;
docEl.style.fontSize = (clientWidth / 7.5) + 'px';
};
if(!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
⼩⽶移动端使⽤⽅案(基于720的设计图)
!function(e){
var t = e.document,
n = t.documentElement,
i = e.devicePixelRatio || 1,
a = "orientationchange" in e ? "orientationchange" : "resize",
d = function(){
var e = n.getBoundingClientRect().width || 360; //  BoundingClientRect()⽅法返回元素的⼤⼩及其相对于视⼝的位置。
(1 == i || e > 720) && (e = 720), n.style.fontSize = e/7.2 + "px" // ⼩⽶就是6啊设计图都是安卓 720*1280界⾯
};
n.setAttribute("data-dpr", i),
t.addEventListener && (e.addEventListener(a, d, !1), "complete" === t.readyState ||
t.addEventListener("DOMContentLoaded",
function() {
setTimeout(d)
}, !1)
)
} (window)
flexible移动端使⽤⽅案
;(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 (metaEl) {
console.warn('将根据已有的meta标签来设置缩放⽐例');
var match = Attribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[1]);
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
var content = Attribute('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 = 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;
}
docEl.setAttribute('data-dpr', dpr);
if (!metaEl) {
metaEl = ateElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = ateElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
function refreshRem(){
var width = BoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
< = = rem;
}
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 (adyState === 'complete') {
doc.body.style.fontSize = 12 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
doc.body.style.fontSize = 12 * dpr + 'px';
}, false);
}
refreshRem();
flexible.dpr = win.dpr = dpr;
<2px = function(d) {
var val = parseFloat(d) * ;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(d) {
var val = parseFloat(d) / ;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
}
return val;
}
})(window, window['lib'] || (window['lib'] = {}));
⼿机淘宝适配⽅案(基于750的设计图)
!function(e, t) {
var n = t.documentElement,
d = e.devicePixelRatio || 1; // 设备DPR
function i() {
var e = n.clientWidth / 3.75; // iPhone 6 布局视⼝375
n.style.fontSize = e + "px"
}
if (function e() { t.body ? t.body.style.fontSize = "16px" : t.addEventListener("DOMContentLoaded", e)}(),
i(),
e.addEventListener("resize", i),
e.addEventListener("pageshow", function(e) { e.persisted && i() }), d >= 2){
var o = t.createElement("body"), a = t.createElement("div");
a.style.border = ".5px solid transparent", o.appendChild(a), n.appendChild(o),
1 === a.offsetHeight && n.classList.add("hairlines"), n.removeChild(o)
}
}(window, document)
2. vw/vh
vw/vh是基于Viewport视窗的长度单位,这⾥的视窗(Viewport)指的就是浏览器可视化的区域,视⼝单位包括以下4个vw : 1vw 等于视⼝宽度的1%
vh : 1vh 等于视⼝⾼度的1%
vmin : 选取 vw 和 vh 中最⼩的那个
vmax : 选取 vw 和 vh 中最⼤的那个
假如你的设计图是750px的宽度,从vw、vh的原理上看100vw=750px,即1vw=7.5px,我们可以根据设计图上的px值转换成对应的vw的值;可以使⽤vw适配我们的页⾯的地⽅:
容器适配,可以使⽤vw
⽂本的适配,可以使⽤vw
⼤于1px的边框、圆⾓、阴影都可以使⽤vw
内距和外距,可以使⽤vw
兼容性问题(在移动端 iOS 8 以上以及 Android 4.4 以上获得⽀持,并且在 x5 内核中也得到完美的全⾯⽀持),所以仍有多种机型会存在兼容性的问题,如果不考虑这些兼容性的问题,可以⼤胆使⽤vw。
3. 百分⽐
百分⽐做⼿机适配的⽅法是⼦元素相对于⽗元素的百分之多少,做⼿机端的适配,整体布局可以实现不同屏幕的缩放,但元素内的字体以及位置难以做到不同屏幕上的放⼤和缩⼩,百分⽐布局只适合布局简单的页⾯,定制化要求⽐较⾼复杂的页⾯实现很困难。
4 媒体查询
媒体查询是早期使⽤的⼿机适配⽅案,通过查询设备的宽度执⾏不同的css代码,展⽰设计图的UI;针对移动和PC维护同⼀套代码时使⽤的较多,例如使⽤Bootstrap做响应式布局时,底层使⽤的就是媒体查询。该⽅案缺点是代码量⽐较⼤,维护不⽅便,做定制化需求时不能很好的满⾜效果,以及为了兼顾移动端和PC端各⾃特有的交互⽅式不能单独使⽤。
总结
随着移动端的发展会出现更多的适配⽅案,⽬前主流的仍是rem做⼿机端的适配,随着浏览器对vw的⽀持,使⽤vw做⼿机端的适配也是不错的选择,如果你担⼼你的移动端项⽬有更好的兼容性以及更好的适配不同的设备,请选择rem作为你的适配⽅案,如果不⽤考虑兼容性的问题可以使⽤vw作为您的⽅案,加⼊你的公司需要使⽤响应式布局移动和PC维护同⼀套代码,可以考虑使⽤基于媒体查询适配⽅案外加less 和sass减少⼯作量。百分⽐做⼿机适配只能做简单的页⾯。
参考资料

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。