PX
px
是一个绝对单位,不相对于谁,只受平台 dpi 影响。cm
、pt
之类的也都是绝对长度,但与 px
这个抽象单位不同的是它们都是物理单位,1pt
则是 1/72
英寸,而 1
英寸换算到公制是 2.54cm
,在 CSS 中所有的物理单位会直接映射到像素,在 96dpi
下 1in = 2.54cm = 96px
1cm = 37.8px
。
EM
em
是一个相对单位,相对于当前元素的 font-size
(如果当前元素没有 font-size
或者 font-size
是相对单位,则先继承父辈的字号,再计算 em
)。也可以说,在 font-size
中使用是相对于父元素的字体大小,在其他属性中使用是相对于自身的字体大小。不管怎么样,要想计算 em
的大小,要先确定当前元素具体的 font-size
。
1 | <div style="font-size: 12px; line-height: 1.5em"> |
上面例子中,span
先继承父元素 font-size
,再计算自身 font-size
,即 3em * 12px = 36px
,width 为 4 * 36px = 144px
。另外,对于相对单位属性的继承,要在父辈元素先计算为具体值,再继承,div
的 line-height
为 1.5em * 12px = 18px
,所以 span
的 line-height
为 18px
,而不是直接继承 1.5em
。
由于 em
相对于当前元素的字号大小,而且字号会继承,这导致不能统一管理基础变量,且依赖追溯复杂,不适合在整个页面中使用,只适用于做局部缩放的场景。
历史上,因为 IE 不支持 px
为单位的缩放,故使用 em
来做缩放。Richard Rutter 在 How to size text using ems 和 How to Size Text in CSS 中做过详细的介绍。
1 | window.getComputedStyle(document.querySelector(':root'), null).fontSize; // 16px,Chrome 上最小支持的字号为 12px |
以 <html>
的 font-size
为基准,浏览器默认的字号为 16px,换算为 em 即 1em = 16px
、12px = 0.75em
、10px = 0.625em
,为了方便 font-size
的换算,可将 html 字号设为 font-size: 62.5%
(即 16px * 62.5% = 10px
),或者直接 font-size: 10px
,这样 1em = 10px
、1.2em = 12px
、1.4em = 14px
。
1 | // 10 ÷ 16 × 100% = 62.5% |
随着浏览器的更新换代,这种做法早已被淹没在历史尘埃中。
Percent
一般情况下 %
相对于包含块(containing block),在应用于字体大小时,相对于父字体大小。
包含块的确定:
1 | * 对于普通定位元素就是父元素 |
需要注意的是 padding
、margin
如果设置了百分比,会发现左右和预期一样,用的父元素宽度的百分比,但是上下用的也是宽度百分比,而不是想象中的高度的百分比。另外 percent
在被后代元素继承时继承的是百分比计算后的值,而不是原百分比,比如 line-height 120%
和 1.2
在被继承时。
REM
rem
相对于根元素 font-size
的单位。引入它是为了解决 em
依赖追溯困难,计算复杂的问题。而 rem
是相对于根元素 <html>
,依赖简单,只需要在根元素确定一个参考值。
1 | // 10 ÷ 16 × 100% = 62.5% |
虽然 em
、rem
相对于 font-size,但是并不单单只能应用于 font-size
。另外,所有的 em
、rem
、percent
渲染的时候,都会被转为 px
,因为 px
是计算机矢量图渲染成像的原理。
rem
常用来做移动端适配。
VW、VH
vw
是 CSS3 引入的单位,相对于视口的宽度,视口被均分为 100 单位的 vw
,1vw = 1%
窗口宽度。vh
同理。常用来配合 rem
做移动端适配。
总结
各个单位都有各自的优缺点,取决于场景,不能脱离场景谈应用。例如 em
、rem
、vh
、vw
、 percent
这些相对单位,比较适合做尺寸联动适配。