web移动端布局的那些事儿
随着Hybrid App的兴起,移动端web开发变得火热起来。web页面相比于App原生页面具有可移植性强、开发效率高、迭代速度快的一些优势,让大部分的App都会内嵌一些web页面。
web的移动端开发和PC开发最大的区别就是在布局上有所不同。本文通过两个方面,布局单位和解决一像素问题两个方面阐述了如何移动端布局。
布局单位
针对较为简单的内容展示页面,使用flex构建页面结构,px作为页面布局的基本单位,足以满足需求。
在面对px无法实现的复杂页面时,主张采用rem作为移动端布局的主要单位。介绍完如何使用rem布局之后,讲述了为什么不采用vw作为主要布局单位。
如何使用rem布局
rem是指相对于根元素的字体大小的单位。html默认的font-size是16px,那么1rem就代表了16px。
根据屏幕宽度设置根元素的字体大小之后, 在布局时使用 rem 单位来布局,就可以达到自适应的目的。
先来看一下js代码是如何设置html标签的 font-size的。
(function() {
function setRootFontSize() {
var docEl = document.documentElement;
var viewportWidth = docEl.getBoundingClientRect().width;
docEl.style.fontSize = viewportWidth / 750 * 100 + 'px'; // 设计稿宽度为750
}
setRootFontSize();
window.addEventListener('resize', setRootFontSize);
})();
为了方便设计稿到rem的换算,在计算根元素字体大小的时候,将视口宽度除以设计稿宽度,在代码示例中代码宽度为750。
浏览器最小字号是12px,为了防止计算结果过小,导致页面出现问题。在这里将计算结果乘以100。
在书写css的时候,只要将设计稿宽度除以100加上rem即可。
例如,一个div在宽度在750像素下,测量的宽度为175px,按照下面的方式来写。
div {
width: 1.75rem;
}
这种根目录字体大小的计算方式,让设计稿测量长度换算到rem十分简单。完全不需要px2rem等构建工具帮助转换,降低了项目的构建成本。
为什么不采用vw
vw作为新出的视口单位,100vw等于视口的宽度。非常适合响应式布局,但是vw有着两个劣势。
-
vw对低版本手机的兼容性问题,并且vw的polyfill具有性能问题。viewport-units-buggyfill的实现原理是通过
document.styleSheets
将所有的样式表全部遍历一边,将视口单位换算成px之后,重新写入html中。如果页面样式比较多,计算量比较大。这将对不支持vw的低端手机造成巨大的性能压力。 -
vw不够灵活,无法限制页面最大宽度或者最小宽度。在兼容pad的时候,防止页面过宽,页面中响应式元素过大。通常需要限制一个最大宽度。达到最大宽度之后,居中显示。使用vw构建的web页面,无法实现此类需求。
解决一像素问题
css中的px并不是真正的物理像素,在做1px的边框或者分割线的时候,如果直接使用1px是无法做出设计师想要的效果的。
目前比较流行的一个解决方案是,通过meta标签设置viewport,将页面按照dpr(设备像素比)完成缩放。
var dpr = window.devicePixelRatio;
<meta
name="viewport"
content="width=device-width,initial-scale=1 / dpr,user-scalable=no"
>
这样设置之后,将会影响外部引入的UI组件。并且也会影响使用用px来描述大小的文字。
防止在dpr高的机型上字体变小,dpr低的设备上字体变大,只能为根元素添加dpr属性,通过描写多种css来实现。
document.documentElement.setAttribute('dpr', window.devicePixelRatio)
p {
font-size: 16px;
}
[dpr=2] p {
font-size 32px;
}
[dpr=3] p{
font-size: 48px;
}
所以推荐在写1像素边框的使用,直接使用0.5px来代替1px,这种方式不会造成副作用,并且从肉眼来看,和设计稿相差无几。