CSS单位
本文最后更新于 2025年8月2日 下午
参考:
概览
人们最熟悉同时也最简单的应该是像素单位(px)。它是绝对单位,即 5px 放在哪里都一样大。而其他单位,如 em 和 rem,就不是绝对单位,而是相对单位。相对单位的值会根据外部因素发生变化。比如,2em 的具体值会根据它作用到的元素(有时甚至是根据属性)而变化。因此相对单位的用法更难掌握。
开发人员,即便是经验丰富的 CSS 开发人员,通常也不愿意使用相对单位,包括经常提到的 em。em 值变化的方式使其难以预测,不如像素简单明了。
在 Web 环境下,用户可以设置浏览器窗口的大小,而 CSS 必须适应这种窗口大小。此外,当网页打开后,用户还可以缩放网页,CSS 还需要适应新的限制。也就是说不能在刚创建网页时就应用样式,而是等到要将网页渲染到屏幕上时,才能去计算样式。
这给 CSS 增加了一个抽象层。我们无法根据理想的条件给元素添加样式,而是要设置无论元素处于任意条件,都能够生效的规则。现在的 Web 环境下,网页需要既可以在 4 英寸的手机屏幕上渲染,也可以在 30 英寸的大屏幕上渲染。
响应式——在 CSS 中指的是样式能够根据浏览器窗口的大小有不同的“响应”。这要求有意地考虑任何尺寸的手机、平板设备,或者桌面屏幕。
相对单位就是 CSS 用来解决这种抽象的一种工具。我们可以基于窗口大小来等比例地缩放字号,而不是固定为 14px,或者将网页上的任何元素的大小都相对于基础字号来设置,然后只用改一行代码就能缩放整个网页。
长度
长度:一种用于测量距离的 CSS 值的正式称谓,它由一个数值和一个单位组成。
长度有两种类型:绝对长度和相对长度。百分比类似于长度,但是严格来讲,它不是长度。
- 绝对单位:值放在哪里都一样大。
- 相对单位:值会根据外部因素发生变化,浏览器会根据相对单位的值计算出绝对值,即计算值。
绝对长度
一般应在输出尺寸已知时使用绝对长度。
CSS 支持几种绝对长度单位,最常用、最基础的是像素(px)。不常用的绝对单位是 mm(毫米)、cm(厘米)、in(英寸)、pt(点,印刷术语,1/72 英寸)、pc(派卡,印刷术语,12 点)。
这些单位都可以通过公式互相换算:1in
= 25.4mm
= 2.54cm
= 6pc
= 72pt
= 96px
。
像素是一个具有误导性的名称,CSS 像素并不严格等于显示器的像素,尤其是在高清屏视网膜屏下。尽管 CSS 单位会根据浏览器、操作系统或硬件适当缩放,在某些设备或用户的分辨率设置下也会发生变化,但是 96px 通常等于一个物理英寸的大小。
某种设备上一个像素的大小不一定与另一种设备上一个像素的大小完全相等。
相对长度
em
em 是最常见的相对长度单位,适合基于特定的字号进行排版。在 CSS 中,1em 等于当前元素的字号,其准确值取决于作用的元素的字号属性值(font-size 属性值)。
设置 padding、height、width、border-radius 等属性时使用 em 会很方便。这是因为当元素继承不同的字号或用户改变了字体设置时,这些属性会跟着元素均匀地缩放。
这就是 em 的好处。可以定义一个元素的大小,然后只需要改变字号就能整体缩放元素。
em 用在内边距、外边距及元素大小上很好,但用在字号上就会很复杂。
定义字号
谈到 font-size 属性时,em 表现得不太一样。当前元素的字号决定了 em。使用 em 定义某元素字号时,font-size 将根据继承的字号(父元素的字号)来计算。
对大多数浏览器来说,默认的字号为 16px。准确地说,medium 关键字的值是 16px。
em 的复杂之处在于同时用它指定一个元素的字号和其他属性。这时,浏览器必须先算字号,然后使用这个计算值去算出其余的属性值。这两类属性可以拥有一样的声明值,但是计算值不一样。
当用 em 来指定多重嵌套的元素的字号时就会产生意外的结果。为了算出每个元素准确值,就需要知道继承的字号,如果这个值是在父元素上用 em 定义的,就需要知道父元素的继承值,以此类推,就会沿着 DOM 树一直往上查找。
rem
rem 是 root em 缩写。rem 不是相对当前元素,而是相对于根元素的单位。不管在文档什么位置使用 rem,1.2rem 都会有相同的计算值:1.2 乘以根元素的字号。由于默认字号对某些用户而言很重要,尤其是对视力受损的人,故应该始终用相对单位或者百分比设置字号。
与 em 相比 rem 降低了复杂性。实际上 rem 结合了 px 和 em 的优点,既保留了相对单位优势又简单易用。那是不是应该全用 rem 抛弃其他选择呢?答案是否定的。在 CSS 里,答案通常是“看情况”。rem 只是工具包中的一种工具。
拿不准时,一般用 rem 设置字号,px 设置边框,em 设置其他大部分属性,尤其是内边距、外边距和圆角。这样字号可预测,同时还能在其他因素改变元素字号时,借助 em 缩放内外边距。用 px 定义边框也很好用,尤其是想要一个好看又精致线时。这些都是在设置各种属性时常用单位,但是它们仅是工具,在某些情况下用其他工具更好。
视口
em 和 rem 都是相对于 font-size 定义的,但 CSS 里不止有这一种相对单位。还有相对于浏览器视口定义长度的视口相对单位。
视口:浏览器窗口里网页可见部分边框区域,不包括浏览器的地址栏、工具栏、状态栏等。
- vh:视口高度的 1/100。
- vw:视口宽度的 1/100。
- vmin:视口宽、高中较小的一方的 1/100。
- vmax:视口宽、高中较大的一方的 1/100。
相对视口的单位对大部分浏览器而言是较新的特性,因此当你将它跟其他样式结合使用时,会有一些奇怪的 bug。
定义字号
相对视口单位有一个不起眼的用途就是设置字号,但它比用 vh 和 vw 设置元素宽和高还要实用。
calc()
函数内可以对两个及其以上的值进行基本运算。当要结合不同单位的值时,calc()
特别实用。它支持的运算包括:加(+)、减(−)、乘(×)、除(÷)。加号和减号两边必须有空白,因此建议养成在每个操作符的前后都加上一个空格的习惯。
可以用 calc()
函数结合 em 和 vw 两种单位定义 font-size。打开网页,慢慢缩放浏览器,字体平滑地缩放。em 保证最小字号,vw 确保字体会随着视口缩放。我们不用媒体查询就能实现大部分响应式策略。不仅省掉三四个硬编码的断点,而且网页上的内容也能由视口流畅地缩放。
百分比
百分比类似于长度,但是严格来讲,它不是长度。
需要知道的是,在 CSS 中,子元素中的百分比到底是谁的百分比。需要分情况讨论。
height、width
在子元素的 height 当中使用百分比,是相对于直接父元素的 height。
在子元素的 width 当中使用百分比,是相对于直接父元素的 width。
top、bottom、left、right
在子元素的 top 和 bottom 当中使用百分比,是相对于直接非 static 定位(非默认定位)的父元素的 height。
在子元素的 left 和 right 当中使用百分比,是相对于直接非 static 定位(非默认定位)的父元素的 width。
padding、margin
在子元素的 padding 当中使用百分比,不论是垂直方向或者是水平方向,都是相对于直接父元素的 width,而与父元素的 height 无关。
在子元素的 margin 当中使用百分比,不论是垂直方向或者是水平方向,都是相对于直接父元素的 width, 而与父元素的 height 无关。
border-radius
在子元素的 border-radius 当中使用百分比,是相对于子元素自身的 width。
除了 border-radius 外,还有比如 translate、background-size 等都是相对于子元素自身的 width。
颜色
- HSL
- RGB
- RGBA
- HSLA
- 十六进制(通常称 hex)
无单位
有些属性允许无单位的值(即一个不指定单位的数)。支持这种值的属性包括 font-weight 、line-height、 z-index(700 等于 bold,400 等于 normal 等)。任何的长度单位(px、rem 等)都可以用无单位的值 0,因为这些情况下单位不影响计算值,即 0px、0%、0em 均相等。
一个无单位的 0 只能用于长度和百分比,比如内边距、边框和宽度,而不能用于角度值,比如度或者时间相关的值,比如秒。
line-height 属性比较特殊,它的值既可以有单位也可以无单位。通常我们应使用无单位数值,因为它们继承的方式不一样。
继承的一个怪异特性:当一个元素的值定义为长度(px、em、rem 等等)时,子元素就会继承它的计算值。当使用 em 等单位定义行高时它们的值是计算值,传递到了任何继承子元素上。如果子元素有不同的字号,且继承 line-height 属性,就会造成意想不到的结果,如文字重叠。
使用无单位的数值时,继承的是声明值,即在每个继承子元素上会重新算它的计算值。这样得到的结果几乎总是我们想要的。我们可以用一个无单位的数值来给 body 设置行高,之后则不用修改,除非有些地方想要不一样的行高。
自定义属性
层叠变量的自定义属性(CSS 变量)给 CSS 引进了变量的概念,开启了一种全新的基于上下文的动态样式。你可以声明一个变量,为它赋一个值,然后在样式表的其他地方引用这个值。
如果刚好用了内置变量功能的 CSS 预处理器,比如 Sass 或者 Less,可能就不太想用 CSS 变量了。千万别这样。新规范里的 CSS 变量有本质上的区别,它比任何一款预处理器的变量功能都多。
定义
要定义一个自定义属性,只需要像其他 CSS 属性那样声明即可。
变量名前面必须有两个连字符(–),用来跟 CSS 属性区分,剩下的部分可以随意命名,且变量必须在一个声明块内声明。如:
1 |
|
使用
调用 var()
函数就能使用该变量。其还接受第二个参数,用于指定备用值。如果第一个参数指定的变量未定义,那么就会使用第二个值。如:
1 |
|
如果 var()
函数算出来的是一个非法值,对应的属性就会设置为其初始值。
动态改变
自定义属性不只是为减少重复代码提供了一种便捷方式,它真正的意义在于,自定义属性的声明能够层叠和继承:可以在多个选择器中定义相同的变量,这个变量在网页的不同地方有不同的值。
如,可以定义一个变量为黑色,但在某个容器中重新将其定义为白色。那么基于该变量的任何样式,在容器外部会动态解析为黑色,在容器内部会动态解析为白色。
自定义属性就像作用域变量一样,因为它的值会被后代元素继承。
用 JS 改变
还可以使用 JavaScript 在浏览器中实时访问和修改自定义属性。
1 |
|
探索
自定义属性是 CSS 中一个全新的领域,开发人员刚刚开始探索。因为浏览器支持有限,所以还没有出现“典型”的用法。
值得注意的是,在不支持自定义属性的浏览器上,任何使用 var()
的声明都会被忽略。需要为这些浏览器提供回退方案。