值和单位
屏幕分辨率:指在屏幕的横纵方向上的像素点数量。
// 比如:分辨率为1980*1080
// 意味着水平方向含有1920个像素点,垂直方向含有1080个像素点
设备像素(device pixels) :设备屏幕的物理像素,表示屏幕的横纵有多少像素点。和屏幕分辨率是差不多的意思。
设备像素比(DPR) :表示1个css像素等于几个物理像素。
// 计算公式:DPR=物理像素数/逻辑像素数(css像素,px)
// 在浏览器中,可以通过window.devicePixelRatio来获取当前屏幕的DPR
像素密度(DPI/PPI) :也叫显示密度或屏幕密度。从技术角度说,DPI只出现在打印或印刷领域;PPI只存在于计算机显示领域。
// 计算公式:像素密度=屏幕对角线像素尺寸/物理尺寸
// 比如:分辨率为750*1334的iPhone6来说,像素密度为:
// PPI=Math.sqrt(750*750+1334*1334)/4.7=326ppi
设备独立像素(DIP) :是针对Android设备衍生出来的。原因是安卓屏幕尺寸繁多,为了显示能尽量和设备无关而提出此概念。它是基于屏幕密度计算的,认为当屏幕密度是160的时候,PX=DIP。
// 计算公式:DIP=PX*160/DPI
PX:表示css中的像素。它是基础长度单位。其他长度单位会自动被浏览器换算成px。对于设备而言,它是一个相对单位,不同设备像素比,会表示不同的物理像素数。
常见的单位,还有em、rem、vw、vh等。
em:是一个相对单位。有两层意思:
- 在font-size中用em表示的时候,是相对于父元素的font-size大小的。比如父元素
font-size:16px
,当子元素指定font-size:2em
,则子元素font-size计算后是font-size:32px
。 - 在其他属性中(比如:width/height/padding/margin)使用则是相对于自身的字体大小。
浏览器会给html根元素设置一个默认的font-size=16px。所以当全局都使用em表示长度时,1em=16px。
<div>
<p></p>
</div>
<style>
div{ font-size: 2em; }
p{ font-size: 2em; }
</style>
<!--
如上,会根据html根元素默认的font-size:16px来计算
div计算后font-size=2*16=32px;
p会根据父级div计算,font-size=2*2*16=64px;
-->
rem:rem和em的区别,rem相对的是HTML的根元素html的font-size来计算的。
vw和vh:vw和vh分别是相对于屏幕视口宽度和高度而言的长度单位。
// 1vw=视口宽度均分成100份中1份的长度
// 1vh=视口高度均分成100份中1份的长度
// 100vw=window.innerWidth
// 100vh=window.innerHeight
vw和vh的出现,使得多了一种写自适应布局的方案,不再局限于rem。另外:
// vmin: 取vw和vh中的较小值
// vmax: 取vw和vh中的较大值
自适应布局方案
方案一:flexible
原理是通过js获取视口宽度,也就是clientWidth,分成10份,用一份的宽度设置font-size。然后根据设备屏幕的DPR,设置合适的body的font-size大小(防止继承的font-size属性值过大,影响页面布局效果)。
这种方法已经被官方废弃了。因为它是动态设置font-size,所以屏幕越大,字体也就越大,会多少影响布局。另外如果通过媒体查询的方式适配平板,一些属性会有问题,比如max-width,需要单独计算设置font-size,否则无效。而且现在vw和vh被广泛支持,用js的方式也就被废弃了。
方案二:postcss-px-to-viewport(vw)
原理是用vw做适配,1px占视口宽度的百分比转换vw。1vw代表的是视口宽度的百分之一,有配置文件可以配置视口大小,要转换的单位等。本质上就是等比例缩放,比如375px宽的视口,元素宽37.5px,转换成vw就是10vw。
这个方法存在的问题和flexible的类似,也会随着屏幕越大,页面各部分所占比例也会等比放大,当适配平板的时候,会影响布局,可能会遮挡信息。这个方法可以配置媒体查询是否转换,所以比flexible好一些。
方案三:postcss-px-to-viewport(rem)
原理是用rem适配,1px占视口宽度的百分比转换rem。这个方法与之前的方法区别是,利用固定根html的font-size加rem的方式,防止在平板等大屏上因为比例放大影响页面布局等问题。这个方法在转换rem的时候有个注意点,rem需要根据font-size计算出对应的px,所以乘以font-size后实际的px值比预想的大,比如:
// 375的视口宽度
// 1px = 1/375 = 0.2666666666666%
// 100px = 26.66666666666% = 26.66666666666rem
// 即,预想用26.66666666666rem表示100px
// 当font-size = 16px
// 26.66666666666rem = 26.66666666666*16 = 426.6666666666656px
// 即,实际计算出来大了四倍多
所以,在配置postcss-px-to-viewport的配置文件的时候,视口宽度要相应的扩大对应的倍数。即:
{
unitToConvert: 'px', //需要转换的单位,默认为"px"
// viewportWidth: 375, // 视窗的宽度,对应设计稿的宽度
// viewportUnit: 'vw', // 指定需要转换成的视窗单位,使用 vw
// fontViewportUnit: 'vw', // 字体使用的视口单位
viewportWidth: 1599.96, // 视窗的宽度,对应设计稿的宽度(扩大对应倍数后)
viewportUnit: 'rem', // 指定需要转换成的视窗单位,使用 rem
fontViewportUnit: 'rem', // 字体使用的视口单位
}
这种方法能够很好的兼容小屏设计稿适配平板等大屏幕场景。
方案四:rem+vw
这个方法本质上也是等比例缩放,用vw表示根html的font-size,这样页面布局就会随着屏幕变大变大。然后根据媒体查询设置不同的font-size,去兼容大屏幕下的页面布局。计算方法跟postcss-px-to-viewport(rem)一样:
// 375的视口宽度
// 1px = 1/375 = 0.2666666666666% = 0.2666666666666vw
// 100px = 26.66666666666vw
// 1rem = 100px = 26.66666666666vw
其中,用1rem代表100px,是为了防止小于浏览器最小字体。所以,在编写代码的时候,需要根据设计图的元素大小除以100,来换算成rem。最后,利用媒体查询去设置不同屏幕下的合适的font-size值来兼容页面布局。
这种方法最灵活,可以根据自己的需要去设置不同的表示单位,想用rem用rem,想用px用px。缺点就是当需要转换第三方ui框架单位的时候,就很麻烦,需要手动一一修改。
总结
总结下来,感觉虽然方案很多,但本质思路都差不多。随着浏览器的支持度和兼容性越来越高,flexible方案可以作为历史阶段的产物放弃掉了。具体使用哪种场景,还是要看具体的开发场景,如果不需要兼容大屏,postcss-px-to-viewport(vw)就可以了,基本不需要考虑别的。否则呢,就在postcss-px-to-viewport(rem)和rem+vw中选择合适的,前者可以支持转换第三方ui单位方便些,后者自由度更高些。
那就见仁见智,萝卜白菜吧。一点小总结,如果有哪里不对的,欢迎大佬指正讨论!!!