什么是适配?
适配:在不同尺寸的手机设备上,页面相对性的达到合理的展示(自适应)或者保持统一效果的等比缩放(看起来差不多)
适配的方法:
1 | 1、百分比适配 |
百分比适配
width:宽度的百分比是相对于父盒子width内容宽的比。没有父盒子就是相对于浏览器的宽。
height:高度的百分比是相对于父盒子height内容高的比。
padding、margin:padding和margin不管任何方向百分比都是相对于父盒子width内容宽的比。
border:不能书写百分数
子盒子如果绝对定位,width百分比参考的是距离最近,且有定位的父盒子的width(算上padding.);
height百分比参考的是距离最近,且有定位的父盒子的height(算上padding.);
padding,margin百分比参考的是距离最近,且有定位的父盒子的width(算上padding.);
viewport缩放适配
把所有机型的设备独立像素(CSS像素)设置成一致的。
比如说,一张设计图是按照iPhone6设计的,iPhone6的分辨率是750x1334,其设备独立像素(CSS像素)就是375x667,那么如果项目网页只想在iPhone6这种分辨率的设备里使用的话,我们代码中像素直接按照设计稿那样给定像素大小就行了。但是这样子的页面放到了其他分辨率、其他设备独立像素(CSS像素)的设备中去的时候,页面就乱套了,比如iPhone6 plus的分辨率是828x1472(设备独立像素(CSS像素)是414x736)。
这时候,如果能将所有机型的设备独立像素(CSS像素)都设置为一致的,比如全设置为iPhone6的375x667,然后代码样式按照375x667的设计稿去给大小,这样网页在所有机型设备中都能做到适配。
1、viewport需要通过js动态的设置(不能直接把device的值设置成数值)
2、通过设置比例(初始比例以及缩放比例),把宽度缩放成一致的
1 | <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"> |
上面代码中的initial-scale就是缩放比,缩放比=css像素/viewport视口宽度。
为了把所有机型的设备独立像素(CSS像素)设置成一致的,就需要设置 initial-scale 的大小。若我们想把所有机型的CSS像素都设置为iPhone6的标准(375x667),通过公式:缩放比=css像素宽度/viewport视口宽度,我们已知viewport视口宽度375,只要获取到当前机型的CSS像素宽度就可以知道缩放比 initial-scale 到底要设置为多少了。而当前机型的CSS像素宽度实际上就是html标签的宽度。
1 | <head> |
若实现没有写<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
则采用如下代码👇
1 | (function(){ |
缺点:
- 就像在viewport设置宽度的时候,可以把宽度设置成一个固定值一样,会出现所有的设备看上去都是同样的大小,没有分别了,不太好,厂商特意做出各种大小的手机,还要弄成一样,那人家买大屏机有什么意义
- 算出的的值在一些有小数的情况下可能会出现误差
DPR缩放适配
根据dpr的值,把视口进行缩放,缩放到物理像素,也就是把css像素的值设置成物理像素,让所有的设备都变成一个css像素对应一个设备像素。比如iPhone6,设备像素是750x1334,设备独立像素(CSS像素)是375x667,我们就把视口进行缩放,让设备独立像素也变成750x1334,从而一个css像素对应一个设备像素。
1 | (function(){ |
缺点:
- 宽度还是需要用百分比,感觉没什么卵用。
rem适配
讲rem之前先来回顾一下em。
em 作为font-size的单位时,其代表父元素的字体大小,作为其他属性单位时,代表自身字体大小
1、chrom下有最小字体限制,必需为12px,所以这个值不能小于12
2、如果两个一样的元素,但是里面字体不一样,那就不能统一设置了。或者元素字体变化了,就又要统一设置一遍
1 | .em{ |
rem CSS3新增的一个相对单位,是相对于根元素的字体大小,即html的字体大小;
1 | html{ |
rem适配的原理:把所有的设备的宽度都分成相同的若干列,再计算元素宽度所占的份数
rem适配,如果可以根据不同机型的屏幕宽度(设备独立像素CSS像素)确定根节点html的字体大小(即一列的宽度),而1rem就等于html节点的字体大小(1rem即为一列的宽),进而在构造页面的时候可以把设计稿中的宽度 / 1rem所代表的px的值,从而得出具体多少rem(即元素宽度所占的份数)从而达到适配。
1 | /* |
1 | //width: 10rem; 实际切图时候给的值 |
综上可知,rem适配的关键是确定根节点html的字体大小,即所谓的一列的宽度。有两种方式可以确定html的font-sitze,一种通过JS设置,另一种通过媒体查询进行设置。
JS设置根节点font-size(简易版)
1 | /* |
这里再多说一嘴关于切图的事,一般设计稿都是按照设备像素大小进行设计的(为了保证图片高清),切图得到的像素大小要先处以设备的DPR,再进行rem的换算。比如IPhone6的设计稿量出来一个div的宽是200px,则代码中给的px是200/DPR=200/2=100px,否则过大,然后再用这个100px进行rem的换算。
1 | //真正切图时候的方法!!! |
JS设置根节点font-size(最优版)
1 |
|
这个方案有个比较爽的地方就是设计稿量出来多少,直接小数点前移两位即转化为rem的值。举个例子,有个div设计稿量出来宽度是187.5px,那么在代码中就应该为187.5/DPR=187.5/2=93.75px,而html的font-size为50px,也就是1rem=50px,那么93.75px=93.75/50=1.875rem,又绕回来了,直接小数点前移两位就得到rem的值。非常方便,免去了手动除以DPR的步骤。
媒体查询置根节点font-size
利用CSS3媒体查询来手动设置根节点的font-size,苏宁在用,不过我觉得有点low,不方便。
1 | <style> |
hotcss适配
作为一个移动端的项目,必须做好移动端适配,这里使用的方案是hotcss,其原理和rem适配原理是一样的,只不过hotcss.js做得更加精细。下面以vue项目举例。
下载好hotcss文件夹,里面有hotcss.js和px2rem.scss两个文件。hotcss.js在main.js中引入。
另外将样式重置文件common.css放在assets文件夹中,然后在App.vue中引入。
px2rem.scss中:
1 | @function px2rem($px){ |
项目设计图的宽度就是750px。px2rem.scss就是一个函数,用于将px转为合适的rem,设计稿量出一个div宽度为200px,则不必再考虑转化为多少的rem,直接使用width: px2rem(200)
即可。
【补充】sass引入公共文件
对于hotcss中的px2rem.scss文件,每个 .vue 文件都要手动引用它,这样很麻烦,所以我们需要只引用一次px2rem.scss就可以在所有的 .vue 文件中使用,那么要怎么做到呢?
在项目根路径下新建文件 vue.config.js:
1 | // vue.config.js |
配置完成之后,就可以保证所有的页面都可以使用这个px2rem.css而无需每个页面都手动引入。
每次修改了 vue.config.js 的时候,都要重新启动项目。
这里我踩了一个坑,在配置sass的时候漏了分号。
vw、vh适配
vw:Viewport’s width的简写,1vw等于视口宽度的1%
vh:Viewport’s height的简写,1vh等于视口高度的1%
vmin:取vw和vh中最小的值
vmax: 取vw和vh中最大的值
vmin 和 vmax 一般很少用到。
ios 8之前和Android 4.4之前的版本都不支持vw、vh适配,这也是其之前不火的原因,现在设备基本都是很新的系统版本了,除非要考虑很旧的版本的兼容,可以放心使用vw适配。
1vw浏览器会自动视为视口宽度的1%,其实就和我们手动将视口宽度(设备的宽度)都100列一个道理。
vw、vh适配一般有两种用法,分别是直接转为vw单位进行使用,另一种是通过vw设置根节点字体大小,页面里的尺寸依然使用rem。
直接使用vw作为像素单位
依旧以iPhone(750x1334)为例子,有:
1 | iphone6 |
1 |
|
这样需要每次都手动去换算px转vm,这个过程很麻烦,我们可以模仿hotcss来通过一个函数来替我们换算,我采用scss预处理器来实现这个函数。
现在VSCode中安装两个插件Sass和EasySass,安装完成之后,每当我新建一个scss文件修改并保存之后都会自动生成对应的css文件。
新建index.scss文件:
1 | @function vw($px){ |
关键代码就是👇
1 | /** |
这样,我们直接可以将从750px的设计稿中量出来的宽度187.5放入这个vw函数中,实现类似hotcss那样的便捷的使用。。生成的index.css内容如下:
1 | body { |
其自动转为了合适的vm。因此随后的所有的宽度都可以使用vm()来进行适配。
vw设置根节点字体大小,其他使用rem
相比于前者,这种vw适配方案更加流行。
在iPhone6(750x1334)为基准的rem适配里,html的fontsize的值设为了50px,具体参见上文中的【JS设置根节点font-size(最优版)】,然后设计稿中量出来多少px,就将小数点前移两位即为对应的多少rem。那么我们可以将50px换为vw,在iPhone6中1vw = 375/100=3.75vw,则50px = 50/3.75=13.333333333333334vw。我们直接将html的fontsize设置为13.333333333333334vw,然后就可以做到所有机型都适配了。如下所示:
1 |
|
相比之下省去了一大段设置html的fontsize大小的JS逻辑代码,更加便捷。
存在的问题
字体默认大小过大和图片错位
1 | <style> |
这时因为html的fontsize设置了大小,导致默认字体大小变大。同时这一设置还会造成图片错位的现象。
1 | <style> |
如上图所示,我并没有给img设置任何padding、margin或者定位等位置信息,它就是发生了错位。这时因为图片默认相对字体对齐,而我们在html中设置了字体大小是一个会非常大的值,所以图片也因此发生了错位。
解决办法就是在body中设置默认的字体大小为12px;这一就不会有上述的情况发生了。