开始之前
需要了解的知识有:
简单粗暴的粗略版移动端自适应
昨天说的粗糙的方案,现在写个栗子。重温一下那个思路:
- 获取设备宽度width
- 跟据设备宽度设置rem的值(1rem=width/倍数),设置body的font-size即可,即font-size = width/倍数
- 设计稿上的px等比换算成rem
核心代码:
1 | let docEl = window.document.documentElement; |
之后就可以根据设计稿进行换算啦。就假设设计稿给出的是375px,这时候计算出1rem=37.5px。
然后假设有一个div的宽度是120px,这时候可计算出width = 120px/37.5 = 3.2rem。
1 | div{ |
完整代码:
1 | <template> |
看几个效果截图:
至此,完成一个简易版的移动端自适应方案,但是,这个方案存在几个问题,首先就是兼容性问题,还有视网膜1px的问题也没做处理,还有就是。。设计稿给的每个以px为单位的属性,都要手动计算转化为rem,很麻烦。
基于Vue移动端自适应方案
基本思路也是上面的例子的思路,但是用到了2个包。
淘宝-lib-flexible:通过动态设置meta和动态设置font-size来实现自适应,解决了上述例子存在的问题。
px2rem:自动计算实现了px向rem转化。
安装依赖
安装flexible:
1 | npm install lib-flexible --save |
引入flexible:在项目入口文件main.js中添加如下代码:
1 | import 'lib-flexible' |
安装px2rem-loader:
1 | npm install px2rem-loader --save-dev |
配置px2rem-loader:
在vue-cli生成的文件中,找到以下文件 build/utils.js,如下图添加配置 :
1 | const cssLoader = { |
px2rem-loader用法:
1 | 直接写px,编译后会直接转化成rem ---- 除开下面两种情况,其他长度用这个 |
重启项目
就能直接按照设计稿上的标注做了。
源码如下,就不截图了:
1 | <template> |
Rem存在的问题
- 开头要引入一段js代码,单位都要改成rem(font-size可以用px),计算rem比较麻烦(可以引用预处理器,但是增加了编译过程,相对麻烦了点)。pc和mobile要分开。
- 会出现出计算出小数的情况,不同浏览器的行为表现可能不同。
- 若手机修改了默认字体大小,可能会出现意想不到的情况,布局错乱。
剖析flexible
1 |
|
1px问题
成因
这个问题本来不是特别理解成因是什么,不过刚刚同学给我解释了,大概明白了。
- 设备独立像素:设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css像素),然后由相关系统转换为物理像素。
- 物理像素:一个物理像素就是显示器上最小的物理显示单元,在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。
- 像素比(devicePixelRatio dpr):设备物理像素 / 设备独立像素,由于不同的手机拥有的像素比也不尽相同,因此一个css像素占据的物理像素个数也是不一样,也就是说css中的1px并不等于移动设备的1px (有人说是为了降低颗粒感,增强用户体验)。
UI设计师设计的时候,画的1px(真实像素)实际上是0.5px(css)的线或者边框。但是他不这么认为,他认为他画的就是1px的线,因为他画的稿的尺寸本身就是屏幕尺寸的2倍。假设手机视网膜屏的宽度是320x480宽,但实际尺寸是640x960宽,设计师设计图的时候一定是按照640x960设计的。但是前端工程师写代码的时候,所有css都是按照320x480写的,写1px(css),浏览器自动变成2px(真实像素)。
那么前端工程师为什么不能直接写0.5px(css)呢?因为在老版本的系统里写0.5px(css)的话,会被浏览器解读为0px(css),就没有边框了。所以只能写成1px(css),实际在屏幕上显示出来就是设计师画的1px(真实像素)的2倍那么宽,所以设计师会觉得这个线太粗了,和他的设计稿不一样。在新版的系统里,已经开始逐渐支持0.5px(css)这种写法。所以如果设计师在大图上设计了一个1px(真实像素)的线的话,前端工程师直接除以2,写0.5px(css)就好了。
解决方案
0.5px边框
由于存在兼容问题,可通过js检测浏览器能否处理0.5px边框,如果可以,给html标签元素添加个class。
优点:简单,不需要过多的代码。
缺点:无法兼容安卓设备,ios8以下的设备。
1 | if (window.devicePixelRatio && devicePixelRatio >= 2) { |
动态设置viewport
淘宝也是这种解决方案。
优点:所有场景都能满足,一套代码,可以兼容基本所有布局。
在devicePixelRatio = 2 时,输出viewport:
1 | <meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no"> |
在devicePixelRatio = 3 时,输出viewport:
1 | <meta name="viewport" content="initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no"> |