移动端适配方案
移动端适配方案是一个老生常谈的话题,但是对于不同的项目、不同的业务场景可能会需要不同的适配方案来进行移动端适配,向下兼容的baseline也需要提前订好。
整体宽高
其实移动端适配就和下面的玩具一样,对应的形状塞到对应的容器里面就好了。但是有点小小的问题,就是这些积木的大小可能和容器不太一样,对于前端来说,这些积木不是用木头做的,而应该是用橡皮泥做的。
业务环境是决定整体项目的适配方案的核心因素。一套代码到底需要兼容多少环境是在项目开始架构的时候就需要确定的。
程序员交友网站,github主站可以明显的看到,所有的内容都被限制到了一个980像素的内容区域里面。
而其移动端也也很明显的是一个单独的布局方式,整体宽度不再限制,即使到了iPad Pro这种宽度到达1024像素的设备上,仍然会占满整个屏幕。
而淘宝的主站和github类似,分为移动端页面和PC端页面,PC端页面同样有着左右的留白,这也是为了让用户能够在宽屏的时候将注意力集中在中间区域。
当前大部分站点都采用UA来判断用户的设备,然后定向到PC或者H5页面。
两者的唯一不同点在于:淘宝会更加严格地将页面直接重定向到另外一个链接,而github则是加载了一个不同的CSS文件进行渲染。当然,这两种方案其实没有本质的差别,而单独的H5页面可以在客户端站内进行更好地复用。
所以,如果有足够的开发人员,开发适用于两种设备类型的页面是比较友好的方案。如果你的移动客户端是基于webview开发的话,那么H5页面还可以直接嵌入到webview中作为展示。
宽度适应
对于整体宽度,正常移动设备的宽高比都比较协调,而像iPad这种设备,其宽度过大,导致了正常的H5页面在上面显示会有比较奇怪的效果。比如淘宝的主站在iPad上的显示效果,可以看到上下两块的navigator被拉长了很多,导致了效果不好。但是如果考虑到成本问题,iPad用户更多地会使用APP来进行访问,所以H5页面的样式重要性就被缩减了。而github移动版对于宽屏设备的适配就会做得更好。
有兴趣的话,可以去看看淘宝的H5页面,这个页面有一个很有趣的地方,这个地方后文会讲到,这里先提一下:
除了宽度仍旧占满屏幕宽度的方案,设置屏幕的最大宽度可以保证在宽屏设备上的显示效果,但是留白的部分就需要考虑处理方案。
由于有了固定最大宽度,仅仅需要对于超过宽度的具有留白的设备进行特殊处理(可以是背景、功能按钮等),中间具有最大宽度的部分就可以进行代码复用。
视口
考拉团队的这篇blog写的已经非常清楚了,感谢考拉的小伙伴给我们提供了便宜的海淘还有这么好的文档产出lol:
PC
桌面浏览器中,正常的视口宽度就是整个浏览器的窗口宽度,会随着浏览器窗口的伸缩而缩放。默认情况下HTML标签会占满整个视口,如果没有设置HTML的静态width的话。
如果采用之前所述的,PC端页面设置最大宽度的话,那么当视口在最大宽度之外的时候缩放的话,不会影响可见区域的显示效果,但是如果缩小到比最大宽度小的时候,原页面的布局方案就很重要了。弹性布局和百分比的布局方式能够在页面缩小的时候,保证页面的布局不会崩溃。
布局视口
在手机上,视口与移动端浏览器的宽度不再关联,而是完全独立的了。我们称其为布局视口。
整个页面可能会变得很大,然后只有一部分显示在设备的可见区域内,整个页面的大小叫做Layout Viewport。这个大小可以通过document.documentElement.clientHeight/clientWidth
来获取。
PPK这篇很早的文章对于视口进行了非常清晰的描述。
上图可见,Layout Viewport的宽高其实是可变的,当通过手势缩放页面的时候,Layout Viewport就会发生变化,当页面缩放到和设备的可见区域大小一致的时候,Layout Viewport就刚好等于Visual Viewport了。
可见视口
Visual Viewport其实很好理解,就是整个屏幕的可见区域大小。由于设备的物理像素,也就是CSS中的pt
单位是固定的,页面在移动端被缩放了之后,页面中的CSS像素分布在设备上也发生了变化。
理想视口
Ideal Viewport其实是上面两者的结合,当我们将Layout Viewport的宽度设置成屏幕的宽度,就保证了页面中CSS像素点的恒定。
这里就用到了移动端适配常用的<meta name="viewport" content="width=device-width">
这个标签可以保证在移动端设备中,页面的宽度与屏幕宽度相同。
缩放
在手机上进行放大的时候,页面中的CSS像素不变,但是可见视口的像素比例发生了变化,但是禁用缩放会导致某些用户的体验较差。保持缩放比例在一定范围之内比较合适。
整体布局
基于如上所述的内容,结合目前的业务内容--主要针对移动端设备进行适配,采用设置最大宽度,并且在meta
标签中设置理想视口,可以保证在移动设备以及PC上面的整体布局效果。
内容布局
目前对于移动端适配的内容布局效果是这样的:
- 百分比,所有需要动态调整的元素宽高采用百分比,字号固定像素。
- rem,通过计算或者JavaScript获取到设备像素/CSS像素的比例,确定根元素的字体像素,然后所有单位根据根元素字体像素进行rem设置,确定大小。而基础rem会根据设备变化而变化。
- vw,根据当前设备的Visual Viewport宽度作为100vw,然后得出单位vw的宽度,所有元素按照vw为单位进行样式排布。
- Media Query:通过断点来进行不同宽度区间的设备样式适配。
以上几个方法各自都有各自的好处,我们可以看一下实际应用时候的效果:
百分比
使用百分比作为内容大小的标准,在大部分条件下是可行的,百分比可以很好地让元素乖乖呆在自己的位置,无论屏幕的宽度大小。
但是文字就存在非常大的问题了,由于文字是固定大小,在屏幕dpr变化的时候,文字的CSS像素不变,就导致了文字在页面中的占位发生了变化。这样的结果就是,文字过多或者屏幕dpr过小的时候,会发生溢出;但是如果按照小屏幕为基准,又会发生字体太小这种情况。
百分比在当前移动端适配排版的时候,更多地会作为section
级别元素的兼容排版。这个也要和设计稿中的效果相关,如果设计稿中要求一个元素定宽,那么就直接用px
来保证宽度就可以了。
rem
rem
这个单位和之前常用的em
有点类似,唯一的区别在于rem
及基于根元素的font-size
来进行计算的一个相对值。em
存在很多缺点,比如层层嵌套之后,可能就会忘记了上一层的font-size
到底是多大。或者比如像现在的模块化开发,一个路由套在另一个路由里面,甚至找父元素都需要到其他文件中去找。
为了解决em
存在的问题,标准中还有rem
这个单位来帮助排版。所有的元素大小都用rem
来作为单位,然后在页面的根元素中,我们为根元素的font-size
进行确定化地赋值,这样所有的rem
单位都是同一个明确的基准了。当屏幕进行适配的时候,只需要调整这个基准值,就可以保证每个元素的大小自动按照比例调整。
阿里的lib-flexible解决方案实际上就是利用了这个方式,通过给<html>
标签绑定font-size
以及data-dpr
属性来进行整个页面的适配。
方案将整个页面宽度分成100份,分成100份的原因可以看下面的另一个方案。每10个单位宽度作为1rem
,也就是整个视觉稿的宽度会被分成10rem
的100份,假如拿到的视觉稿是750px
的,那么1rem
就代表75px
。这样得到的比例系数就是75/750
,也就是每次在进行设计稿到CSS的转换的时候,只需要对设计稿的像素值/10就可以得到对应的rem
值。
通过一个预先加载的JavaScript脚本,计算根节点的字体大小,document.documentElement.style.fontSize = window.innerWidth / 10 + 'px';
,然后我们在写页面代码的时候只需要将原始的像素值/基准值就可以得到对应的rem
单位了。当然每次都要按计算器肯定是不行的。如果想方便使用的话,可以用less或者sass这种预处理器来处理页面。
@function px2rem($px)
// 这里将设计稿的px转换为rem,
@return ($px / $unit-px) * 1rem
// 根据设备的dpr进行字体适配
@mixin font-dpr($font-size)
font-size: $font-size
[data-dpr="2"] &
font-size: $font-size * 2
除了元素宽高可以得到比较好的还原,对于文字大小的适配也比较重要,由于每个设备的dpr不同(这里尤其是iOS设备),直接导致了很多文字在iPhone6+上显示正常,而在iPhone5上面却文字过大,导致文字溢出,上面的less mixin
就是进行字体样式适配的。
这种方法结合了sass
的函数功能和rem
的适配,再加上必要的百分比以及media query可以得到比较好的移动表现。
这是使用这种方法在iphone6上的显示效果,具体的整体显示效果可以戳这里,rem基准样式示例
如果对于文字在各种平台上的显示效果不满意,可以通过上面说的sass
的mixin
来让文字根据dpr
进行断点渲染。
而这样存在的问题就是仅仅适用于移动端,并且不能够进行横屏适配,因为横屏之后,页面的宽度发生了变化,但是基准值却还保持着原本绑定到根节点上面的基准值。
vw(是最终解决方案吗?)
首先看看vw
的浏览器支持情况吧,can i use vw支持情况,使用这个单位意味着你放弃了IE11以下的PC用户,在现在一个主要兼容移动端的世界里,并没有太大的副作用(这里吐槽一句,其实PC端的兼容远远要比移动端来的方便。移动端奇奇怪怪的分辨率以及2x,3x的屏幕,还有苦逼的ipad、横屏让我每次做兼容的时候想一跃解千愁)。
vw
自身将整个可见视口横向分成了100份,每一个单位就是1vw
,这个单位最大的优势就是在移动端的时候,无论是竖屏或者横屏,vw
永远都是针对于横向的,比rem
的方案好在当屏幕大小发生变化(顺便兼容了以后的可调节屏幕大小的移动设备[手动斜眼])的时候,不会让页面崩掉。
对于移动设备来说,比如iphone6+的375px
CSS像素宽度,1vw
就等于3.75px
,通过这个单位可以解决上面的依赖于脚本绑定根元素font-size
的问题,在竖屏和横屏下面都有比较好的效果。
在通过vw
解耦了CSS和JS之后,那么vw
是否可以独立解决所有问题呢?
// 首先,我司的设计稿目前都是以750px为宽度,实际为iPhone6+的375px为基准
$w-base: 375px
$w-base-design: 750px
@function px2vw($px)
@return ($px / $w-base-design) * 100vw
首先,上面的sass
代码可以根据你设计稿上面的px
单位转换为vw
单位值。当然最简单的办法还是直接按照视觉稿上面像素进行输入,然后直接输出对应的vw
值啦。vscode和sublime当然会有已经做好的插件,但是个人并不是很喜欢这种方式,这样你就没办法得到这个视觉稿原本的像素值了。在后期进行维护的时候会增加很多很多很多麻烦。这就是写起来爽,改起来火葬场吧。。。vw的效果可以看下面的codepen。
所以说优势和劣势呢
目前来说,vw
是肯定不适合单独使用的,毕竟页面中还是有很多元素需要绝对的大小定位的。px
永远是必不可少的,视觉不可能让你所有的东西都自适应。
那么vw
能够解决什么问题呢?首先是大部分取代%
在CSS中的使用,百分比在CSS中存在很多歧义,对于宽度,上下边距,左右边距,内外边距的处理方式不尽相同。即使是老练的前端有时候也得思考一下当前的百分比到底是根据什么确定的。而vw
则是一个绝对的数值,仅仅根据一个不太可能变化的屏幕宽度来确定。
而百分比主要解决的弹性问题,就是vw
着力解决的问题。
vw
不能够兼顾所有的情况,所以这个单位目前还并不是最终的解决方案,还是需要和其他单位合作来帮助页面能够更加优雅地显示出来。
结论
虽然根据实现出来的效果,几种方法可能没有什么太大的效果差别,但是最大的问题在于,需要实现这种效果需要多么复杂的代码呢。
CSS的兼容性不在于解释器上,而是在于设备的屏幕上面。大部分时间不仅需要将页面展示在用户的面前,而是需要将页面稳定且优雅地展示给用户。
无论是百分比,rem
还是vw
,都是进行局部容器元素定位的,作为最底层的叶子元素或者单元元素来说,更多时间还是会使用px
来尽量还原视觉稿。
长远考虑这个问题,vw
在仅进行移动端访问的情况下效果拔群,因为不考虑兼容,只需要考虑适配问题。工程中到底使用哪个方法进行,取决于大部分业务需要兼容的环境。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。