尽管我们可以使用设备独立像素来保证各个设备在不同手机上显示的效果类似,但这并不能保证它们显示完全一致,我们需要一种方案来让设计稿得到更完美的适配。
flexible方案
flexible方案是阿里早期开源的一个移动端适配解决方案,引用flexible后,我们在页面上统一使用rem来布局。
它的核心代码非常简单:
// set 1rem = viewWidth / 10function setRemUnit () { var rem = docEl.clientWidth / 10 docEl.style.fontSize = rem + 'px'}setRemUnit();
![346672889c1830a7e092273193f5db21.png](https://i-blog.csdnimg.cn/blog_migrate/ca74a5e97917a6b824052c47948d44f2.jpeg)
rem 是相对于html节点的font-size来做计算的。
通过设置document.documentElement.style.fontSize就可以统一整个页面的布局标准。
上面的代码中,将html节点的font-size设置为页面clientWidth(布局视口)的1/10,即1rem就等于页面布局视口的1/10,这就意味着我们后面使用的rem都是按照页面比例来计算的。
这时,我们只需要将UI出的图转换为rem即可。
以iPhone6为例:布局视口为375px,则1rem = 37.5px,这时UI给定一个元素的宽为75px(设备独立像素),我们只需要将它设置为75 / 37.5 = 2rem。
当然,每个布局都要计算非常繁琐,我们可以借助PostCSS的px2rem插件来帮助我们完成这个过程。
下面的代码可以保证在页面大小变化时,布局可以自适应,当触发了window的resize和pageShow事件之后自动调整html的fontSize大小。
// reset rem unit on page resizewindow.addEventListener('resize', setRemUnit)window.addEventListener('pageshow', function (e) { if (e.persisted) { setRemUnit() }})
![1420b0e5ffe05dbfa6f0dbc67b99164f.png](https://i-blog.csdnimg.cn/blog_migrate/9ef92abb7f13e20ae73187fd476f291a.jpeg)
由于viewport单位得到众多浏览器的兼容,上面这种方案现在已经被官方弃用:
lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。
下面我们来看看现在最流行的vh、vw方案。
vh、vw方案
vh、vw方案即将视觉视口宽度 window.innerWidth和视觉视口高度 window.innerHeight 等分为 100 份。
上面的flexible方案就是模仿这种方案,因为早些时候vw还没有得到很好的兼容。
- vw(Viewport's width):1vw等于视觉视口的1%
- vh(Viewport's height) :1vh 为视觉视口高度的1%
- vmin : vw 和 vh 中的较小值
- vmax : 选取 vw 和 vh 中的较大值
![a27e44e030cb5dcaa2437aaa8bd057a2.png](https://i-blog.csdnimg.cn/blog_migrate/727b9bf7cebb2a9384c04f520791c58b.jpeg)
如果视觉视口为375px,那么1vw = 3.75px,这时UI给定一个元素的宽为75px(设备独立像素),我们只需要将它设置为75 / 3.75 = 20vw。
这里的比例关系我们也不用自己换算,我们可以使用PostCSS的 postcss-px-to-viewport 插件帮我们完成这个过程。写代码时,我们只需要根据UI给的设计图写px单位即可。
当然,没有一种方案是十全十美的,vw同样有一定的缺陷:
- px转换成vw不一定能完全整除,因此有一定的像素差。
- 比如当容器使用vw,margin采用px时,很容易造成整体宽度超过100vw,从而影响布局效果。当然我们也是可以避免的,例如使用padding代替margin,结合calc()函数使用等等