我认识的很多前端的初学者停留在PC端页面的阶段,但其实移动端开发也是非常重要的一个模块。而在移动端开发中最需要我们注意的,就是适配问题。这篇文章对完全没有接触过移动端开发的小伙伴也比较友好,我们从源头开始,让没有接触过移动端的小伙伴先有一个宏观上的认知,然后我们再细致的聊聊移动端适配的那些事儿(文章比较长,大家可以分阶段食用)。
大家最开始学习前端,一定是从PC端页面做起的,同样的道理,移动端无非就是把PC端的网页搬到手机上而已,通常我们把这样的项目叫做app(手动尴尬~~),但是app的开发也是有他的渊源的,大部分情况下我们开发的app只是其中的一种,app的种类共有三种:
总结一下,移动端的开发,大部分情况下还是依赖于浏览器的,那么我们只不过是把网页放在了手机上而已。
了解了移动端开发的大概,我们发现它和PC端的没什么区别,都是在浏览器中搞事情,那为什么要针对移动端做适配的工作呢?移动端之所以能受此殊荣,一定是有原因滴。(先上一波图,大家感受一下)
1983年,史上第一部上市销售的手机摩托罗拉8000X,它使用的是单色LCD屏,属于液晶屏技术,通过电压去控制液晶材料的排布与遮光性,使其拥有像素的属性去展示图像。
1994年,IBM Simon,同样是LCD屏,屏幕的大小为4.5英寸 × 1.4英寸,分辨率为160 × 293,但是第一次去除了物理按键,完全采用触摸屏操作
2010年,iPhone4,3.5英寸,分辨率为960×640,采用了视网膜显示屏(即retina屏),保证屏幕在正常视距下不会出现颗粒感,同时retina屏将设备像素比(dpr)提升至2,移动端适配需要多考虑dpr的因素
2011年,第一代三星Galaxy Note,5.3英寸的屏幕几乎是当时最大的屏幕,800×1280分辨率,当时对其界定与智能手机和平板电脑之间,但是对移动端设备屏幕大小做出了突破。
2014年,夏普Aquos Crystal,5英寸LCD显示屏,分辨率为1280 x 720,屏占比达到了78.5%,第一代全面屏手机。
2015年,三星Galaxy S6 Edge,5.1英寸,2560 x 1440的AMOLED显示屏,第一代曲面屏手机。
2017年,苹果iPhone X,屏幕尺寸5.8英寸,2436 × 1125 像素分辨率,458 ppi,屏幕的样式做出了突破性的刘海屏,自此之后,水滴屏、挖孔屏…等屏幕相继推出,在保证功能的情况下极大的提高的屏占比。
2019年,华为Mate X,第一次推出折叠屏,正面屏幕为6.6英寸,背面为6.38英寸,这就要求对此类设备做出额外的适配,要实时感知屏幕大小的变化。包括之后推出的卷轴屏…
现在大家能理解为什么要做移动端的适配了吗?从硬件的角度看,移动端设备在以极快的速度更新更无敌的体验,包括:音质、相机像素、屏幕分辨率、屏幕大小、存储能力、运行能力、续航能力…,而如此参差不齐设备屏幕和分辨率无疑对前端开发是非常不友好的,我们的页面会在五花八门的手机有完全不同的展示,甚至直接扭曲掉。ok,移动端适配就是来避免这种情况的。与大小形状差距不大的电脑显示器,大家能理解为什么要针对移动端做适配了吗?
至此,我们已经大概知道了移动端的发展背景,以及我们要解决的问题。那么在做具体工作之前,我们还要储备一些基础的知识,包括开发中用到的单位,有关移动端中一些属性的理解。
这些单位相信大家都不陌生,我也就不用说的太详细了,重点要理解的是rem和vw/vh,这个我会在后面着重讲。
广义的理解,viewport就是设备屏幕上能展示网页的区域(可能是整个浏览器,可能是一个app的webView),但是viewport不局限在浏览器可视区域中。相反,一般的viewport会比浏览器可视区域更大,为了方便移动设备能正常展示PC端的网页,各个浏览器厂商设置了不同的viewport默认值。所以在开发中要注意app所用的浏览器内核以及其版本,确定viewport的默认值。
狭义上,viewport可以有三种理解。
说了这么多,可能还有有人不理解,为什么要给一个viewport三种定义?他们之间是什么关系?我师傅也问过我这个问题,其实viewport作为一个抽象的概念,它的含义有很多,但是我们开发中只会参照ideal viewport去做页面。理解的小伙伴们可能发现了,这三个viewport并不是并存的,而是开发者对其理解思考的过程,一步一步更加完美的实现适配,这样说大家应该可以理解了吧。
移动端适配是一个漫长的发展过程,前人对此总结出多种适配方案,下面我们就其中最具有代表性的来分析。
这是比较古老的一种方案,现在%作为css中的一个单位,除了保证100%宽度时使用一下,它的用武之地越来越小了。虽然%能够实时的适应屏幕的大小,但是依旧不受宠。原因也很简单,举个栗子,当我们出现比较多的标签嵌套时。
看似每个div的宽度都是30%,但是出来的效果却是这样的。%的特性就是这样,我们定义任何一个元素的宽高时都需要考虑到其父元素的宽高,想想都复杂,这种方案用起来太费劲。
当然,不仅仅是因为上面的原因,还有一个缺点就是”%“不能应用在字体上,这就导致字体不能跟着”%“的节奏去适配,要么字体大小永远不变,要么只能根据js判断屏幕宽度,然后动态改变字体大小,抛开性能问题不谈,这样的操作就相当复杂。
稍微理解一下,百分比方案之所以不流行的原因,就是因为这个单位的参照物不一致,没有一个统一的标准,所以我们要定义一个统一的标准。显然,把标准宽度设置为屏幕宽度是最好不过,我们假设屏幕宽度为10a(a是我们假想的单位),那么在代码中任何第一个地方使用2a,都能实现整个屏幕20%的效果,并不需要考虑父元素。
不幸的是,css并没有a这个单位,于是rem诞生了,按照上面的理解,rem的统一参照标准是根字体(即html的font-size)大小,我们只需要根据屏幕的变化改变根字体的大小即可实现良好的适配。
当然,问题一定是存在的,有兴趣的小伙伴可以自己试试,随着屏幕的变化,用rem定义宽度的元素也会随着变化,这个变化的趋势是线性的,简言之就是”等比缩放“的。但是我们的浏览器中的字体大小的变化并不是线性,请看下图。
另外,一般情况下我们会把根字体的大小设置为屏幕大小的1/10,对于元素来说,1rem或者0.1rem都是可以接受的,但是字体就比较傲娇了,由于rem换算出的px精度很差,特别是针对屏幕尺寸比较奇怪的手机,字体的大小又只能适应整数px(浏览器会对此做出相当强硬的取整),那么我们页面中的字体布局样式很可能事与愿违。
很遗憾,rem方案并不能对字体的大小做出良好的适配。如果你能理解上面的两个方案,这里都不需要分析,vw/vh一定会存在上面的问题,那么我们为什么还要推出这种方案呢?想想上面两种方案的特性,vw/vh是不是把它们两个整合起来了呢?它拥有统一的参考标准(layout viewport),并且这个标准就是屏幕本身,而不是需要我们自己配置的根字体。所以,我的理解是,vw/vh综合了以上两种方案的特性。它的出现让适配更加的纯粹,它不需要太多js的干预,减小的与js之间的耦合性。
这是一套比较成熟的适配方案,详细的介绍请转至这里。
如果想要真正了解flexible的发展,请看这里。
如果你看过了lib-flexible,会发现它的缺点也很明显,一般我们设计稿中提供的单位全部是px,但是在lib-flexible中大部分要使用rem,中间的换算问题需要人为解决,比较复杂。所以我们要搭配postcss-pxtorem来帮助我们完成换算,开发时直接使用px作为单位。postcss-pxtorem安装后做一些webpack配置即可。
module.exports = {
plugins: {
'postcss-pxtorem': {
//设置根字体的大小
rootValue: 75,
//表示哪些属性可以接受px变为rem
propList: ['*'],
}
}
}
需要注意的是,在使用Echarts,canvas之类组件的时候,用js代码定义宽高,单位会省略,默认是px。此类的px并不会被postcss转化为rem,而是单纯的指css像素,所以Echarts内字体大小用数字定义时,字体的大小不会是实时变化的。
学习过PC端响应式页面的小伙伴,一定用过bootstrap这类UI库,其中的UI组件可以自动实现响应式。大家可以去对比一下,在响应式中,不仅仅是元素的等比变化,在超过一定临界点的时候,会有全新的页面布局设计,以保证良好的展示和交互。而我们所做的移动端适配,并不会像“响应式”那样频繁的变化页面大小,毕竟屏幕大小能实时变化的手机还是少数。我们的适配操作只需要在项目启动的时候执行一次即可。
讲了这么有关适配的方案也好,思想也好,都是为了让我们的项目更接近完美的展示在不同设备上,而要做到真正的100%,我不能说完全不可能,只能说任重而道远。
移动端适配的学习是一个漫长的过程,不是看几天的文章就能搞懂的,它需要长期的跟踪学习、理解、练习,才能做出更好的适配效果。本文中仍然留下了很多坑,比如:字体的大小到底怎么适配,1px问题,高清图问题… 我也会持续学习更新。看完这篇文章,希望大家能有所收获,也希望大家提出宝贵意见,蟹蟹!