3前端 | 移动端适配问题解决方案

0.108字数 1597阅读 323

本文来自@dduke;地址:https://juejin.im/post/5add7a44f265da0b886d05f8

做为前端开发的程序猿,在开发移动端web应用的时候,对面一堆各色尺寸不一样的屏幕,就有点淡淡的忧伤。

正文从这里开始 ~

20185322173

已上是2018年二月份最新的友盟数据,很明显我们所要实现的就是在上述如此之多的屏幕,都能实现UI大大出的视觉图上的效果。而要实现这样的效果主要有两个难点:

  • 各屏幕适配
  • Retina屏下的细节处理(主要是1px的问题)

flexible + rem

显而易见,该方案是由rem 以及 flexible组成的。rem (font size of the root element)相对于根元素(即html元素)font-size计算值的倍数,flexible 即 flexible.js, 手淘团队提供的一个为该方案屏幕适配而写的一个库,主要实现的功能就是,根据屏幕的宽度给 html 元素设置一个合适的 font-size 值。

怎么样看的不是很懂是吧。让我来用一个页面场景再复述一遍。

正常情况下,我们的UI大大会以iphone6的尺寸为标准,做一套视觉效果图,并在上面进行标注,给到我们的标注图,如下所示:

20185322215

拿到这个图 我们该如何下手呢

  • 先设置 html 元素的 font-size, 这个值我们暂时设置为 font-size: 37.5px,即1rem = 37.5px;
  • 以iphone6为例子,其屏幕宽度为 750px, 整个屏幕的宽度即 20rem = 37.5 * 20px = 750px;
  • 此时手机号的输入框为 490px = 13.06777777rem
  • 依次将页面上的px转换为rem,这样我们就得到了全是rem为尺寸单位的页面

到这里为止是不是就结束了呢 ? 很遗憾的告诉你并不是。为什么 html 元素的 font-size 要设置为 37.5px呢?现在这个界面在iphone6上能完美显示了,在iphone5s,iphone6p能完美显示吗?(iphone6, iphone6s, iphone7. iphone8屏幕没有发生变化,本文直接用iphone6代替了。)

上面的两个问题 我们还有没解决,这个时候就轮到flexible登场了。只需要像如下引入就可实现用js来自动根据屏幕宽度设置 html元素的font-size的值。

<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>

在上述过程中,你会发现,UI给到我们的一般是px标注的图,我们将其转化为rem,这个过程其实会花费很大的计算时间。做为一个合格的程序员,我们应该把这种机械性无脑的操作交给计算机来实现。有很多脚手架工具比如:PostCss的插件postcss-px2rem,在构建的时候自动将我们所写的px转换为rem,大大提升了我们的开发效率。

VW

这个vw的方案,相当而言还比较新。vw 即(viewport width)可视窗口的宽度。之所以把这个方案放在后面来说,是因为viewport在去年(2017年)的时候存在不少的兼容性问题,各个浏览器的支持并不是很好。但是来到了2018年这个时间点,viewport单位意见得到了众多浏览器的支持(80.45%)。

201853222621

接下来就让我们来正式了解下这个方案吧。 vw既然是一个尺寸单位,那它的宽度等于多少呢?等于1%整个屏幕的宽度。举个例子,再次以iphone6手机为例,100vw = 750px => 1vw = 7.5px

再一次那上次的界面做示范

20185322215
  • 根据定义,我们了解了在iphone6手机上 1vw = 7.5px
  • 此时手机号的输入框为 490px = 65.333333vw
  • 依次将页面上的px转换为vw,这样我们就得到了全是vw为尺寸单位的页面

同样的px转换为vw,工具网上也是有很多的...

1px问题

移动端的屏幕不仅仅分辨率有差异,其实还有Retina屏的问题。正常情况下,我们代码里的1px在屏幕上就应该显示一个像素点,但是在Retina屏下则不仅仅是一个像素点。再次拿iphone6为例,其dpr(device pixel ratio)设备像素比为2,css中一个1x1的点,其实在iphone6上是2x2的点,并且1px的边框在devicePixelRatio = 2的Retina屏下会显示成2px,在iPhone6 Plus下甚至会显示成3px。

这样的话,我们就会发现在有些手机上1px明显跟另外的一些手机的1px粗细不一样。 其实大多数的小公司不会扣这样的一个细节,比如说我们公司不会。(__) 嘻嘻……

但是作为一个有追求的前端工程师,我们应该尽量的把事情做的完美一点,(ps.像大公司看齐,在大公司这个细节问题其实是不容忽视的,为了自己以后的发展前途,我们有必要把这个细节完善掉的。)

这个问题的解决方案有很多,个人觉得最简单方面的还是大漠大大的一种解决方案。使用postcss-write-svg插件

@svg 1px-border {
  height: 2px;
  @rect {
    fill: var(--color, black);
    width: 100%; height: 50%;
    }
  }
.example {
  border: 1px solid transparent;
  border-image: svg(1px-border param(--color #00b1ff)) 2 2 stretch;
}

//编译后
.example {
  border: 1px solid transparent;
  border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch;
}

总结

如果仔细看一下的话,会发现之前的rem的方案其实就是模拟了vw的实现方案,两者有非常多的相似之处。在lib-flexible的github上有着这样的一句话。

由于viewport单位得到众多浏览器的兼容,lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。vw的兼容方案可以参阅《如何在Vue项目中使用vw实现移动端适配》一文。

我们可以得到一个很明确的信息,lib-flexible这个方案已经被放弃使用了,我们可以去拥抱vw的那套实现方案。

推荐阅读更多精彩内容