rem, vw, 还是...? 各凭本事的移动端适配方案

16,442

前言

2018年最后的法定假期都已经结束了,我相信大部分正在进行或曾经进行过移动端页面开发的同学都或多或少的了解过使用rem进行移动端页面适配的方案以及使用vw的方案,(没了解过的同学可以参见大漠老师的这两篇文章 使用Flexible实现手淘H5页面的终端适配再聊移动端页面的适配)也面临过在不同适配方案间进行抉择的思考,我个人最近对于移动端适配方案也进行了一轮重新的研究,期间,对各种适配方案也有一些自己的见解,正好记录下来与大家一起分享。

vw与rem方案中的一些思考

所以,移动端适配 = vw or rem ?

当然不是。并不是所有场景下的移动端页面都适合采用vw或rem的方案,这类方案的本质是布局等比例的缩放,让页面在不同尺寸的屏幕下有类似于矢量图片缩放的效果,即保证页面各元素之间位置尺寸的比例关系,并让元素可以清晰地展现。 这样的方案更适合于视觉组件种类较多,视觉设计对元素位置的相对关系依赖较强的移动端页面。其实大部分页面都可以使用rem或vw的方案进行适配,但对于文本内容较多,或者说希望引导用户沉浸浏览的页面,我个人并不推荐使用等比缩放的方案,至少并不推荐完全使用等比缩放的方案,对于文本内容还是应该直接使用px这种绝对长度单位,毕竟在大屏手机上用户希望看到的是更多的内容而不是更大的内容。实际上很多这类的网站也确实是直接使用px结合flex等布局方式进行移动端适配的,这个在后面讨论具体技术方案的时候我会举几个例子。

rem方案到底在做什么?

在各种rem适配方案的实现中,有两个核心的点

  • 设置<meta name="viewport" content="xxx">(可以根据dpr缩放viewport,也可以直接使用1倍的视口大小)
  • 根据当前布局的宽度(通常是viewport宽度, 也可以是被限制的最大/最小布局宽度)来设置html元素的font-size

之前我已经提到过,vw和rem的方案的本质都是“等比例缩放”,因为vw和rem都是相对长度单位(relative length unit),可以很好的满足这个需求。区别是vw是viewport width的1%,而rem是html元素的font-size。当我们让html元素的font-size与viewport width产生了关联后,rem就可以模拟出使用vw进行布局的效果了。所以在rem方案中,我们只是在把rem当做是vw的影子。写作rem,读作vw...(剧情似乎狗血起来了... rem: 当然是选择原谅你们啊)

我rem有话说

那直接用vw不就完事儿了吗?

且慢
且慢,当初之所以使用rem的方案流行开来正是因为在那时viewport units的浏览器支持程度不甚理想(IOS 8+, Android 4.4+ 参见viewport units的caniuse)。而相比较之下rem就好多了(IOS 4.1+, Android 2.1+ 参见caniuse),所以对于vw,在当时的大环境下前端想说爱你不容易。

我想这时候有人要说了:“醒醒兄弟 已经8102年了!” 是的,8102年都快要过去了,对于兼容性要求不是特别高的情况下vw也算是可以见天日了,并且也有一些针对vw的补丁方案,但还有一个问题我们要稍微讨论一下...

vw可以完全替代rem吗?

回答依旧是否定的。单纯使用vw进行布局不能限制布局的宽度,对于有这个需求的场景至少还是需要将vw和rem混用来处理边界情况。下文也会更详细地提到这种方案,这里先按下不表。

现有生产环境中移动端适配方案的一点总结

当我们在苦苦地寻找适合自己的道路时,不妨先抬头看看别人是怎么做的。那么现实世界里各家互联网公司的移动端页面都采用了什么样的适配方案呢?有没有一些比较有特色的绝活儿呢?以下我按照页面实际使用的css长度单位作为划分标准,为大家举一些栗子。

px方案

就像开篇提到的,并不是说移动端就一定要使用相对长度单位,传统的响应式布局依然是很好的选择,尤其在新闻,社区等可阅读内容较多的场景直接使用px单位可以营造更好地体验。px方案可以让大屏幕手机展示出更多的内容,更符合人们的阅读习惯。采用这种方案的网站有:

  • 腾讯

    移动端首页主要是新闻内容,需要更好的阅读体验,适合直接使用px进行布局。

  • 知乎

    知乎也是比较典型的追求阅读体验的场景,不出意外的也是直接使用px。

  • 点评

    视觉元素较丰富,依旧采用了px方案,页面基本是flex布局,适配效果很好

  • 头条

    头条的这个方案有点特色,依然会设置html元素的font-size也会加上data-dpr属性并且会对viewport进行scale, 但是最终css的输出还是px,并没有使用rem,并且会对不同dpr下的样式单独定义,如下图所示:

    头条的适配方案
    这样可以解决1px border的问题,文字大小也不会随屏幕尺寸变动(毕竟文本内容较多),虽然我暂时没找到使用到rem的地方,但确实可以在需要的时候对特殊元素做rem方案的布局,不过这种方案应该会造成css文件大小倍增,而且输出这样的css肯定也少不了构建流程插件的支持,算是一种特定的解决方案吧。

看到这里你以为最终输出px就不能做类似于rem/vw的弹性布局了吗,下面就给大家看一手绝活儿...

  • 淘宝

    什么?给我们看了半天文章结果用的是px?

    喵喵喵
    其实聪明的你一定很快就会发现在效果上淘宝移动端的适配方案和rem/vw的方案其实是差不多的,元素的样式都是通过js生成的,虽然单位确实是px,但是方案依旧是以375px宽度的尺寸为基准进行缩放的。原理上应该是一种css in js的方案,只不过把rem方案中设置html元素font-size的过程内化到使用js计算元素style的过程中去了。这样的方案涉及到整体的开发框架上的统一与支持,并不算是一个特别通用的方案。好处可能是直接使用px单位结果更为精确。可以说是一手绝活儿了。当然淘宝旗下还是有非常多的产品线的,也未必是同样的适配方案(比如大漠老师文中的例子),这里只针对这个移动端首页来说。

rem方案

rem方案可以说是比较成熟了,出镜率也较高,也就不再赘述了,总的来说rem方案主要分为两种,一种是缩放viewport的方案,如当年的lib-flexible,可以对1px border等细节问题较方便的处理,但会影响到media query。另一种就是不缩放viewport,对1px boder等问题单独引入处理方案。然后对于基准尺寸下的html元素fong-size也有很多不同的定义方式,这个说起来没什么标准可言,我就随便举几个例子说明吧:

不缩放viewport

(以下说明的rem与px的对应关系都是在屏幕宽度为375px的情况下)

  • 马蜂窝 1rem = 37.5px

  • 小米 1rem = 52.0833px

  • 小红书 1rem = 50px

  • 微博

    1rem = 16px 稍微说明下 微博的font-size是根据media query来生成的

缩放viewport

(以下说明的rem与px的对应关系都是在屏幕宽度为375px, viewport scale 0.5的情况下)

vw方案

来了,终于来了!前面说了这么多关于vw的问题,到底有没有现有的产品在大规模的使用vw的方案呢?兼容方案又是怎么做的呢?

  • 京东

    京东的移动端首页采用了vw+rem的布局方式,元素布局上依然使用rem单位,没有缩放viewport, html元素的font-size则使用vw + px fallback的形式,并且使用media query来限制布局宽度,如下图所示

    正常情况下:

    京东适配方案 正常情况下
    边界情况下
    京东适配方案 边界情况下

  • 网易

    网易的方案和京东基本相同,没有缩放viewport,使用media query,只处理html元素的font-size,并限制布局宽度。

  • 饿了么

    饿了么也是采用的vw+rem的方案,不过对viewport进行了缩放,也没有限制布局宽度,html元素的font-size依然由px指定,但是具体元素的布局上使用vw + px fallbak的形式,如下图所示:

饿了么适配方案

可以看到,使用上述两种vw+rem的方案对现有的rem方案的改动都不会很大,都采用了vw + fallback的方式,兼容性问题得到了保证,只是饿了么的方案可能更需要构建过程中的插件支持(关于这个,后面我给你们解释解释什么叫惊喜)。这样来看,对于大漠老师提出的vw方案中使用viewport-units-buggyfill库进行兼容的做法,我个人就并不是很推荐了,因为该库使用了css content属性进行兼容处理,官方文档中就指出了对部分浏览器的img标签有影响 ,需要全局引入一条css规则。且对于需要正常使用content的情况(如:图标字体)也会引起不可避免的冲突,另外也不支持伪元素的兼容。所以从我个人的角度来说,如果你一定要问我使用怎样的vw适配方案,我会推荐给你上述两种vw + rem的方案。

这就是全部了吗?

当然不是,我只是列举了几个比较典型的移动端适配方案,其实在具体实现的细节上可以自行把握的点还是很多的,适合的终归才是最好的,那颗银弹或许不会出现,但我们的手中也从未缺少过利器。

彩(an)蛋(li)部分

相信大多数同学也是有想法在实际开发中把vw融入到现有的移动端适配方案中的。如我上述提到的两种vw+rem方案,只修改html元素font-size的方案对于已经在使用rem方案的同学来说改动的成本并不大,只需要在原本的media query 里(或js生成style时)在font-size: *px后面加上font-size: *vw就可以了,如需限制布局宽度则需多加一点判断。

而对于饿了么那种在使用到长度单位时同时输出rem+vw的方式,肯定是要通过一点额外的插件来做了。如果你和我一样刚好在使用Stylus作为css预处理器,那我专门写了一个Stylus的插件用来帮你处理这个问题。 这个插件可以让你在开发流程使用px书写css, 和现有的部分插件不同的是,它同时支持多种适配方案的输出,目前支持rem,纯vw方案以及刚才提到的vw+rem方案的输出。并且对不希望转换px的场景做了很方便的处理。也就是说,如果你现在使用rem方案,可以直接替换使用该插件,当你需要切换到vw或vw+rem方案时基本可以做到无缝切换。

具体的使用方式和示例请参见pandaGao/stylus-px-to-relative-unit

懂我的意思吧