likes
comments
collection
share

css布局单位详解 🌲 🎁 ❄️

作者站长头像
站长
· 阅读数 1

CSS长度单位知多少

大部分前端开发者都有靠 px% 闯天下的经历,后来发现 vw vh calc 也是真香,尤其遇到PC端的布局适配场景堪称神器,所以把CSS的尺寸单位都拉出来看一看,在这之前要先搞明白几个概念,比如px到底是绝对单位还是相对单位?

先了解几个概念

分辨率

我们把一张图片无限放大会看到很多小格子,通常把他们叫做像素格,如果有一张图片分辨率是500*500那说明这张图片横向和纵向都是500个像素格。对应到设备屏幕上,屏幕上的格子我们叫它像素点,比如iPhone6的分辨率是1334*750,说明iPhone6的屏幕上有1334*750个像素点。我们通常说的分辨率指的是用户设定的桌面分辨率,这和物理分辨率是有差别的,通常桌面分辨率等于物理分辨率的时候显示效果是最佳的,如果你愿意当然可以把一块1280*768的屏幕分辨率调成640*384

屏幕尺寸

屏幕尺寸一般用英寸表示,英寸是长度单位不是面积单位,我们常说的某设备屏幕是5英寸指的是对角线长度是5英寸,1英寸等于2.54cm。在屏幕尺寸确定的情况下分辨率越高屏幕越清晰。

设备像素(物理像素)

设备像素也叫物理像素,具体指设备屏幕上的物理像素点,屏幕控制显示的最小单位,由设备屏幕决定,单位pt,设备出厂的时候设备像素就已经确定了,且永远不会改变。

设备独立像素(DIP)

设备独立像素是一种被程序所控制的虚拟像素,在Web开发中对应CSS像素,我们把物理像素重新排列,以固定数量的物理像素点来表示一个设备独立像素,一个设备独立像素对应CSS中的1px。

一个单位的设备独立像素(也就是1px)表示N个物理像素,如果固定用一个设备独立像素表示一个物理像素会带来什么问题呢,假设有两块5英寸的屏幕,一块的分别率是500*500,另一块的分别率是1000*1000,因为设备独立像素和物理像素是一比一的关系当把250px的盒子渲染到屏幕上时,在500*500的屏幕盒子占宽度的二分之一,到了1000*1000的屏幕就只占到四分之一,这是完全不同的用户体验。因此我们在物理像素上抽象一个逻辑层,以固定数量的物理像素来表示一个设备独立像素,重新构成页面渲染的像素点。至于多少个物理像素对应一个设备独立像素就需要引入另外一个概念设备像素比(DPR)后面会讲到。

设备像素比(DPR)

设备像素比 = 物理像素 / 设备独立像素 (可以通过JS来获取设备像素比 window.devicePixelRatio)

设备像素比主要用来告诉屏幕1设备独立像素(也就是CSS里的1px)对应在显示器上渲染几个物理像素,当前设备的设备像素比可以用window.devicePixelRatio命令查看得到,如果DPR为2,即1设备独立像素包含2个物理像素。这样我们用CSS设置的1px,不论在什么设备上显示的都是1px,但是这个1px对应的物理像素是不确定的。

DPR并不是开发者控制的,是厂商决定的,这里要引入另外一个概念屏幕像素密度(PPI)后面会讲到,每个固定范围内的PPI会对应一个固定的DPR值(如下表),这也导致了CSS设置的100px在不同屏幕上显示的物理长度会有细微差距。总的来说屏幕像素密度(PPI)越大,设备独立像素对应的物理像素越多,屏幕越清晰。

以iPhone6为例,厂商给出的分辨率(也就是物理像素)是1334*750,DPR是2,我们可以计算得到它的设备独立像素是667*375,也就是Chrome手机模拟器显示的667*375。iPhoneX分辨率是2436*1125,DPR是3,设备独立像素是812*375

我们在PC浏览器上按 Ctrl + 加号 键,改变的就是设备像素比(DPR),可以console.log(window.devicePixelRatio)看一下,DPR变大了,一个设备独立像素(CSS的px)对应的物理像素变多了,所以视觉上页面变大了。

屏幕像素密度(PPI)

屏幕像素密度 = 物理像素 / 屏幕尺寸

屏幕像素密度(PPI)指的是每英寸屏幕所拥有的物理像素数量,屏幕像素密度强调的是每英寸有多少像素点。是衡量设备清晰度的关节指标,乔布斯定义PPI300以上称为视网膜级别,Retina视网膜设备的DPR是2或者3,在开发的过程中就用到了2倍图或者3倍图。下面表格列出了PPI和DPR之间的大致关系。

PPI 区间120-160160-240240-320320+
DPR 值0.7511.52

打印机(DPI)

打印机的墨点,不多做介绍。

CSS长度单位

CSS中长度单位分为两类 绝对单位相对单位,看下W3C对绝对单位和相对单位的定义。

**绝对单位:**绝对长度单位是一个固定的值,它反应一个真实的物理尺寸。 **相对单位:**相对长度单位中的相对二字,表明了其长度单位会随着它的参考值的变化而变化,不是固定的。

绝对单位

  • in(英寸)
  • cm(厘米)
  • mm(毫米)
  • pt(points)
  • pc(Picas)

1in = 2.54cm = 25.4 mm = 72pt = 6pc

绝对单位是固定不变的,有一个固定的物理长度,相互之间有清晰的换算关系,最终在页面渲染时会转换成px,绝对单位常用在印刷打印方向。

对前端开发者来说绝对单位用的最多的也就是mm和cm了,做打印表单业务的时候把页面宽度设置成210mm,这样用户的预览体验和真实打印效果最接近。

相对单位

  • px 像素
  • vw 视窗宽度
  • vh 视窗高度
  • vmin 取视窗宽高较小值
  • vmax 取视窗宽高较大值
  • ex 元素内字符x的高度
  • ch 元素内数字0的宽度
  • em 元素字体高度
  • rem 根元素fontSize
  • % 百分比

px px是相对单位,因为1px在不同设备上渲染的物理像素数量不一致,不同设备上一个物理像素的大小也不一致。为保证阅读体验一致,CSS的px 相对 物理像素 是动态的,px和物理像素之间的关系根据设备像素比(DPR)确定。

有了对上文概念的认识,再来理解CSS的px就容易许多了,我们以 iPhone3gs(480x320)和 4s(960x640)来举例,他俩屏幕尺寸都是3.5英寸,分辨率差了一倍,如果DPR为1在4s上面渲染出来元素会偏小,就像下面这张图所示。但在实际渲染中4s的DPR为2,也就意味着1px会渲染两个物理像素,元素放大了且页面看起来会更加清晰。同时在头像区域就需要提供2倍图,把资源命名成带@2x格式,使用的时候iOS会自己识别,如果不提供2倍图使用1倍图就会放大一倍显示,必然失真。

css布局单位详解 🌲 🎁 ❄️

vw 视窗宽度,1vw表示视窗宽度的1%,响应单位,物理长度会随视窗宽度变化而变化。

vh 视窗高度,1vh表示视窗高度的1%,响应单位,物理长度会随视窗高度变化而变化。

vmin vmin取视窗宽度高度两者更小者,1vmin表示视窗宽度高度两者更小者的1%。

vmax vmax取视窗宽度高度两者更大者,1vmax表示视窗宽度高度两者更大者的1%。

vw、vh、vmin、vmax 这几个单位还是比较实用的,当做一些PC的响应式布局时经常会用到%,但%是基于父元素的,极端情况下父元素可能没有撑开,这时候就得一层一层的去检查,撑开相应的父级,或者做宽高都是100%屏幕的大屏展示系统这种情况用vw、vh都是很合适的。

ex ex表示元素内字符x的高度,一个小写字母,比如“d”,它会有一部分高出来,ex不包括高出来的这一部分的。

ch ch表示元素内数字0的宽度

em em表示当前元素font-size的大小,现代所有的浏览器中,都会有一个默认值,即1em = 16px。

值得注意的一点是影响em变化的因素只有font-size,而影响 ex、ch 变化的因素除font-size外还有font-family,因为font-family的改变也会使得x或者0字符的大小发生变化。

em有继承的特性也就是级联效果,如果当前元素未设置font-size它会继承父元素的font-size,看下面的效果:

<div style="font-size: 12px">
  font-size:12px
  <div style="font-size: 1.2em">
    font-size:12 * 1.2 = 14.4px
    <div style="font-size: 1.2em">
      font-size:12 * 1.2 * 1.2 = 17.28px
    </div>
  </div>
</div>

举一个实际项目中的例子,之前搞富文本编辑器需要控制字体大小,我定义了四种规格分别是 Small、Normal、Large、Huge,父级容器font-size默认是Normal规格设置为16px,剩下的分别是Small0.8em、Large1.2em、Huge1.8em,这样我们调整了父容器的font-size值之后其他规格的字体都会跟着发生变化。

rem rem(root em),相对根元素的font-size是动态的,和当前元素无关,当浏览器解析HTML元素时,会将页面渲染成一个树形结构,<html>节点是最外层的父元素(根节点),rem表示html节点的font-size大小,当根元素未设置font-size值时,默认取16px。

有一个特别的伪类 :root 可以直接选中根节点html,和通过html选择器选中html节点没有任何区别

rem如何使用

rem只是开发者工具箱中的一个工具并不是万能的,一般使用在移动端的响应式布局上,常用来设置字体大小以及部分容器的宽高,边框则用px,容器的布局有时用百分比也能很好解决,rem并不是万能的。

移动端在开始布局之前需要先设置meta标签,来指定默认的缩放比,以及是否允许用户缩放。

<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
  • content="width=device-width 内容的宽度设置为设备宽度
  • user-scalable=no" 是否允许用户进行缩放
  • initial-scale=1 设置页面的初始缩放值
  • minimum-scale=1 允许用户的最小缩放值
  • maximum-scale=1 允许用户的最大缩放值

设置基准值法

设计师一般以iPhone6的二倍图出设计稿,那么设计稿的宽度就是750px,我们设置根的font-size值为 (clientWidth ÷ 7.5)px 此时可以得到下面两个式子:

(clientWidth ÷ 7.5)px = 1rem 750px ÷ 7.5 = 100px

  • clientWidth是设备宽度,是一个动态的值,不管 clientWidth ÷ 7.5 的具体值是多少,因为设置给了根的font-size,所以都是1rem的值;
  • 因为布局是响应式的,容器的宽度占比应该保持一致,设计稿的宽度是750px,100px占设计稿的7.5分之一,在真机上也应该占7.5分之一,也就是1rem;

根据上面两条规则可以得出结论设计稿的100px等于整机的1rem,在做开发的时候量出设计稿中元素的尺寸再除以100,就是css中应该设置的rem值。

根font-size的设置可以用到vw font-size: calc(100vw/7.5),不支持vw的设备可以配合 document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + 'px'

手淘flexible法

flexible是手机淘宝团队的开源解决方案,原理大致就是以设计稿为基准,将设计稿的宽度平分为10份,把一份的宽度设置为根font-size的大小,这样1rem在真机上的宽度和设计稿十分之一的宽度占比一致,感觉上很像vw,同时flexible还支持动态生成meta标签。

flexible具体的解决方案看这篇