CSS 的值和单位是 CSS 另一个独立功能模块,到目前为止,该模块已到了 Level 4 阶段(CSS Values and Units Module Level 4)。今天我们就来聊聊这个模块里的内容。对于 CSSer 来说,对于 CSS 中的值和单位应该不会感到陌生,但大部分同学应该都会把精力集中于单位这一块,事实上也是如此,在这篇文章中,我们所涉及到的大部分内容也是聊单位这一块,对于值这一部分只会花一点点内容略为带过。
CSS的值
在聊 CSS 的值之前,先给大家上一图:
上图只是我们常见的 CSS 样式规则之一。
事实上 CSS 是一门非常神奇的学科。我们在声明任何一个 CSS 的规则都可能会包括:
-
CSS 的选择器
-
CSS 的属性
-
CSS 的属性值
-
CSS 的属性值单位
而我们今天要聊的是 CSS 的属性值和单位。但事实上,CSS 不是每个规则都会同时包含 CSS 的属性值和单位,因为很多属性的值是只具有值,不具有单位的。比如上图的color
属性,他的值就不带单位,但可以是关键词、字符串、函数等。你在写 CSS 的时候可能会涉及到的 CSS 的值会有:
-
数值 :长度值
<length>
,用于指定例如元素width
、border-width
、font-size
等属性的值,这些值可能带有单位,也可能不带任何单位 -
百分比 :可以用于指定尺寸或长度,例如取决于父容器的
width
、height
或默认的font-size
-
颜色 :用于指定
background-color
、color
等 -
坐标位置 :以屏幕的左上角为坐标原点定位元素的位置,比如常见的
background-position
、top
、right
、bottom
和left
等属性 -
函数 :用于指定背景图片或背景图片的渐变,比如
linear-gradient()
、image-set()
等
简单的概括一下:CSS 属性的值有多种,可以是数值、字符串、关键词或函数;同时 CSS 的属性的值可以带单位也可以不带单位 。而且 CSS 的值并不是一成不变的,不同的属性对应的值都会略有不同,比如:width
属性,它的值可以是一个百分比的值,也可以是一个带有数值和单位;color
的值可以是一个关键词,也可以是一个函数值;font-size
可以是百分比、关键词,带有单位的数值;line-height
可以只是一个数值,可以是百分比值,还可以是带有单位的数值等。众多属性不一一列举。
CSS的单位
上面也提到了,CSS 属性值是带有单位,也有不带单位的。而 CSS 的单位对于 CSS 的值有是一个直接影响的。因为 CSS 的单位直接对 CSS 的值的计算是有直接影响的,在 CSS 中单位的之间有一个关系图,如下所示:
为了便于大家更好的理解和记住 CSS 中单位相关的知识点,下图是根据 W3C 规范重新做的划分:
注意,上面这张图有点老了,正如《现代 CSS》的 《现代 CSS 中的相对单位》所述,到目前为止,CSS 相对长度单位主要分为字体相对长度单位 、视窗相对长度单位 和容器查询相对长度单位三种:
-
字体相对长度单位:指的是使用它们的元素(用于本地字体相对长度)或根元素(用于根字体相对长度)的字体度量
-
视窗相对长度单位 :相对于浏览器视窗的尺寸的长度,例如
vw
和vh
等 -
容器查询相对长度单位 :相对于查询容器的尺寸的长度,例如
cqw
和cqh
等
那么在这篇文章中,我们主要围绕着 CSS 中常用单位来展开。介绍这些 CSS 单位使用的场景和使用细节。
绝对单位
在 CSS 中有些单位是绝对值,不受任何屏幕大小或字体的影响。这些单位的显示可能会根据不同的屏幕分辨率而有所不同,因为它们取决于屏幕的 DPI(每英寸上的点数)。绝对单位常用于一些物理测量上。在环境输出已知的情形下非常有用。在 CSS 中,绝对单位包括:px
、in
、cm
、mm
、pc
和pt
等。其中px
是我们最为常见的一个绝对单位。到目前为止,px
在 CSS 的使用中也可以算是主流单位之一。
像素单位被认为是许多其他单位的测量基础。它提供了各种设备中一致的结果。也被认为是最好的设备像素 ,而这种像素长度和你在显示器上看到的文字屏幕像素无关。因为px
实际上是一个按角度度量的单位,即像素角度。
有关于设备像素更多的介绍,请移步阅读《现代 Web 布局》的《下一代响应式 Web 设计:组件驱动式 Web 设计》。
很多时候,px
也常被称为 CSS 像素。它是一个绝对单位,但也可以被视为相对单位,为什么这么说呢?那是因为像素单位相对的是设备像素。在同一样的设备上,每1
个 CSS 像素所代表的物理像素是可以变化的(即 CSS 像素的第一方面的相对性);在不同的设备之间,每1
个 CSS 像素所代表的物理像素是可以变化的(即 CSS 像素的第二方面的相对性)。
根据维基百科的解释:
它是图像显示的基本单元,既不是一个确定的物理量,也不是一个点或者小方块,而是一个抽象概念。所以在谈论像素时一定要清楚它的上下文!
不同的设备,图像基本采样的单元是不同的,显示器上的物理像素等于显示器的点距,而打印机的物理像素等于打印机的墨点。而衡量点距大小和打印机墨点大小的单位分别被称为PPI
和DPI
。
由于不同的物理设备的物理像素的大小是不一样的,所以 CSS 认为浏览器应该对 CSS 中的像素进行调节,使得浏览器中1
个 CSS 像素的大小在不同物理设备上看上去大小总是差不多 ,目的是为了保证阅读体验一致。为了达到这一点浏览器可以直接按照设备的物理像素大小进行换算,而 CSS 规范中使用"参考像素"来进行换算。
1
个参考像素即为从一臂之遥看解析度为96DPI
的设备输出(即1
英寸96
点)时,1
点(即1/96
英寸)的视角。它并不是 1/96
英寸长度,而是从一臂之遥的距离处看解析度为96DPI
的设备输出一单位(即1/96
英寸)时视线与水平线的夹角。通常认为常人臂长为28
英寸,所以它的视角是:
scss
(1/96)in / (28in * 2 * PI / 360deg) = 0.0213度。
由于 CSS 像素是一个视角单位,所以在真正实现时,为了方便基本都是根据设备像素换算的。浏览器根据硬件设备能够直接获取 CSS 像素。
简单介绍一下一臂之遥:我们在使用不同设备输出时,眼睛与设备输出的典型距离是不同的。比如电脑显示器,通常是一臂之距,而看书和纸张时(对应于打印机的设备输出),则通常会更近一些。看电视时则会更远,比如一般建议是电视机屏幕对角线的
2.5
到3
倍长 ------ 如果你是个42
英寸彩电,那就差不多是3
米远。
这样描述对于很多 CSSer 太过于理论,我们还是回到实际中了。比如说我在项目中有一个盒子元素,它的大小是宽高都是150px
,那么我们在 CSS 中常常这么使用:
css
.box {
width: 150px;
height: 150px;
}
虽然说,像素应该是设备和显示器中显示趋于一致,但是他越来越不正确。那是因为,随站 Retina 屏的出现,dpr
不同(设备像素比),对像素和显示器显示会略有不同。比如下图所示:
正因如此,在移动端设计当中,大部分设计都采用2
倍或3
倍尺寸进行设计。
虽然说px
是 CSS 最绝对单位中最常见,使用最频繁的一个单位。而事实上,CSS 中绝对单位不仅仅这一个,还有其他的绝对单位,比如in
(英寸)、cm
(厘米)、mm
(毫米)、pc
和pt
等。其中,in
、cm
和mm
可以和px
直接进行换算:
-
1in = 96px
-
1cm = 37.8px
-
1mm = 3.78px
而pc
和pt
和in
有直接关系:
-
1in = 72pt
-
1in = 6pc
如果你希望pt
和pc
直接和px
进行换算的话,可以借助in
为中间桥梁。比如:
-
1in = 96px = 72pt
,那么1px = 72 / 96 = 0.75pt
-
1in = 96px = 6pc
,那么1px = 6 / 96 = 0.0625pc
可以用一张简单的图来描述绝对单位之间的关系:
在规范中,绝对单位还有一个新单位,不怎么常见,即Q
,1Q
相当于25mm
。它被用于印刷排版。
相对单位
相对单位和绝对单位有所不同,相对单位是相对于另一个长度的长度。使用相对单元的样式更容易离开一个输出环境并适应另一个环境。CSS 的相对单位主要分为两大类,其一是字体相对单位,会根据font-size
进行计算;其二是视窗相对单位,相对于视窗大小来决定。
字体相对单位
字体相对单位主要有em
、rem
、ex
、ch
、cap
、ic
、lh
和rlh
。其中em
、rem
、ex
和ch
是较为常见的字体相对单位。在这里我们也只会介绍这几个常见的单位。
em
起初排版度量时是基于当天字体大写字母M的尺寸的。当改变font-family
时,它的尺寸不会发生任何改变,但是在改变font-size
的大小时,它的尺寸就会发生变化。
在 CSS 中,如果没有任何 CSS 规则影响的前提之下,1em
的长度是:
ini
1em = 16px = 0.17in = 12pt = 1pc = 4.mm = 0.42cm
众所周知,每个浏览器都有一个默认的font-size
大小,而这个值通常是16px
(用户未修改浏览器字号时)。这也就是为什么1em = 16px
的原理所在。
em
还有一点很重要:em
和它们的祖先元素的font-size
有关系。因此,如果祖先元素的font-size
设置为0.5em
,同时它的子元素的font-size
设置为1em
,在这一情景之下计算出来的 font-size
将为会是16 x 0.5 = 8px
:
从上面的简单示例,我们可以得知,随着 DOM 元素的嵌套加深,同时不同层级都显式设置font-size
的值为em
,那将会增加em
计算和转换的复杂度,比如:
在px
和em
之间的转换存有一定的公式在,如下:
css
1 ÷ 父元素的font-size × 需要转换的像素值 = em值
注意,元素自身未显式设置
font-size
时,取父元素的font-size
。
我们也可以借助于 JavaScript,写一个简单的转换函数:
scss
function px2em(pixel,parentFontSize) {
return (pixel / parentSize) + 'em'
}
px2em(10, 16) // => 0.625em
em
单位除了应用于font-size
属性之外,还可以运用于可以使用<length>
值的其他属性,比如width
、margin
、padding
、border-width
和text-shadow
等等。
<length>
是表示距离尺寸的一种 CSS 数据格式。它由一个<number>
后紧随一个长度单位,比如px
、em
、pt
、in
等等。和任何 CSS 尺寸一样,数字和单位之间没有空格。如果<number>
为0
的话,其之后的长度单位是可选的。
如果在非font-size
的属性上使用em
做为<length>
值的单位时,将会受元素font-size
的影响。在众多开发者中有一个比较普遍的语解,认为em
单位是相对于父元素的font-size
。而事实上呢?它们是 相对于使用 em
单位元素的 font-size
。父元素的font-size
可以影响em
值,但这种情况的发生,纯粹是因为继承。
前面也提到过,使用em
单位存在继承的时候,会让我们处理单位的转换时变得比较棘手。
为何要处理单位的转换呢?那是因为我们拿到的设计稿,其度量单位大多数是
px
为单位。如此一来,从设计稿转换到 Web 页面的时候,我们就存在px
转em
这样的一个过程。
从前面的知识中,我们得知,使用em
单位的属性会根据元素font-size
大小来决定。但该元素可能继承其父元素的font-size
,而父元素又有可能继承其父元素的font-size
。因此,以em
为单位的font-size
可能会受到其任何父元素的font-size
大小影响。这个论点在上面的示例中已得到了验证。
既然元素font-size
大小会有变化,那么该元素上使用em
为单位的属性,也将会受到相应的影响。我们来看看相应的示例:
css
div {
width: 20em;
height: 20em;
border: 1em solid;
padding: 3em;
}
你看到的效果如下:
在这个示例中,我们没有在div
元素和其祖先元素显式的设置font-size
,所以该元素的font-size
会继承浏览器的默认font-size
,即16px
。因此在width
、height
、border-width
和padding
属性中的em
会根据16px
做为基准进行计算。因此,最终得到的效果如上图所示。如果我们在div
中嵌套一个子元素div
。得到的效果将如下:
两个div
使用em
的属性,最终计算出来的结果是一样的,只不过子元素div
溢出了父元素div
。如果我们在子元素div
中显式的设置font-size: .5em
,得到的结果将是另外一种:
就此而言,em
单位可以更好的维护和扩展组件的大小。比如,控制组件大小的属性,比如width
、height
、padding
和border-width
等使用em
作为单位时,如果要调整组件大小,可以直接调整组件的font-size
(要是元素自己未设置font-size
时,可以调整其祖先元素的font-size
)。比如下图所示,调整font-size
可以很灵活的控制组件的大小:
rem
rem
相对于em
而言没有那么复杂,他仅仅是相对于根元素<html>
的font-size
计算。W3C 规范是这样描述rem
的:
Font size of the root element!
很多时候,我们可以把rem
作为em
的替代品。特别是在font-size
属性上的运用,但rem
和em
有一个最大的区别:任何值为 1rem
的元素都等于 16px
,当然,其前提是浏览器默认的 font-size
没有被用户重置,或者未显式的给 html
元素设置 font-size
值;另外, rem
可以不管它的父元素的 font-size
如何!
从上图可以看出,就算是body
中显式的设置了font-size
的值,但其并不会影响其子元素h3
的font-size
,h3
的font-size
始终都是相对于根元素<html>
来计算的。
另外,rem
和em
有点类似,能接受<length>
为值的属性都可以以rem
为单位,而且都是相对于根元素html
的font-size
进行计算,并且跟 DOM 的层级没有任何的关系。
em 还是 rem
在实际开发中,很多时候很多同学都会问:
em
好,还是rem
好,应该选择哪个更好?
事实上,这是一个极具争议的一个问题。因为在实际中,一些开发人员完全避免使用rem
,声称使用rem
会使他们的组件缺少模块化;另外一些开发人员则什么都使用rem
,因为喜欢rem
所带来的便捷。那么应该更好的去选择呢:
没有最好的,只有最适合的!
对于是选择rem
还是em
,应该出于理智,在不同的地方使用rem
或em
。事实上,很多成功的案例也证明了这样的观点:
-
如果这个属性根据它的
font-size
来进行测量,则应该选择em
-
其他的一切事物均应该使用
rem
同时,大家也可以根据两者的差异性来进行选择:
-
rem
和em
在客户端中计算出来的样式值(计算样式(Computed Style) )都会以px
显式 -
rem
相对于根元素html
的font-size
计算,em
相对于元素font-size
计算 -
rem
可以从浏览器字体设置中继承font-size
值,em
可能受任何继承过来的父元素font-size
的影响 -
使用
em
应该根据组件的font-size
来定,而不是根元素的font-size
来定 -
在不需要使用
em
单位,并且需要根据浏览器的font-size
设置缩放时,应该使用rem
ex和ch
ex
和ch
是排版单位,这意味着它们的值取决于元素的font-family
。而我们在使用em
和rem
单位时,浏览器会根据元素的font-size
计算它们的值。无论屏幕上显示的是什么字体,浏览器计算出来的值都是相同的。这就是ex
和ch
单位提供更多灵活性的地方。它们要求浏览器在计算值和应用样式之前要确定好引用的font-family
。因为,元素的font-family
样式对ex
和ch
单位值的计算有直接关系和影响。
在印刷术语中,x
高度由字体小写字母的高度决定。这通常用它母x
来衡量,它没有任何上升和下降。字体的font-size
和x
高度之间的关系可以告诉你很多关于字体的比例。
ex
单位的值来自它们所计算的字体上下文的x
高度,x
高度由两个因素决定:font-family
和 font-size
。换句话说,它们等于特定字体在特定font-size
下的x
高。
正如上图,font-family
为Helvetica Neue
设置的font-size
为100px
,那么1ex
大约等于52px
。
ch
和ex
相似,但它不依赖于x
的高度;而是基于字体的字符,从字体的0字形宽度中提取它们的值,它还随字体而变化。如此一来,就有点随意,而0
的宽度通常是对字体的平均字符宽度,这是一个估计值,所以会有点糟糕。
由于ch
单位是一个近似等宽的一个单元,因此在设置容器的宽度是特别的有用。比如说,你想让容器显示特定数量的字符串时,就可以使用ch
单位。
《现代 CSS》的 《现代 CSS 中的相对单位》所述,现代 CSS 中字体相对单位,除了上现提到的单位之外,还有其他一些字体相对单位:
-
rex
:相对于根元素上的ex
单位的值计算 -
rch
:相对于根元素上的ch
单位的值计算 -
cap
:等于第一个可用字体的使用帽高度(cap-height),它大约等于大写拉丁字母的高度 -
rcap
:相对于根元素上的cap
单位的值计算 -
lh
:等于元素的行高(line-height
) -
rlh
:相对于根元素上的lh
单位的值计算,当用于根元素的font-size
或line-height
属性时,它指的是这些属性的初始值 -
ic
:是ch
的东方版本。它是 CJK (中文、日文和韩文)表意文字水
(U+6C34
)的大小,因此可以粗略地解释为"表意文字计数"。在不可能或不实际确定表意文字的大小情况下,必须假定为1em
-
ric
:相对于根元素上的ic
单位的值计算
视窗相对单位
CSS 中除了字体相对单位之外还有视窗相对单位,主要有vw
、vh
、vmin
和vmax
。在了解视窗单位之前,先简单的了解一下视窗的概念,这样有助于我们更好的理解视窗单位。
在 PC 端,视窗指的是浏览器的可视区域,而在移动端中相对来说更为复杂一些,它包括三个视窗:布局视窗 (Layout Viewport)、视觉视窗 (Visual Viewport)和理想视窗(Ideal Viewport):
而我们要说的视窗单位中的视窗指的是:PC 端指的是浏览器可视区域,移动端的是布局视窗(Layout Viewport) :
有了视窗的概念,就可以更好的理解 CSS 中有关于视窗单位,在 CSS 中视窗单位主要有:
-
vw
:视窗宽度的百分比 -
vh
:视窗高度的百分比 -
vmin
:当前较小的vw
和vh
-
vmax
:当前较大的vw
和vh
用下图来描述,大家会更清晰一些:
简单的来看看视窗单位是如何进行计算的。例如,如果浏览器的高是900px
,1vh
求得的值为9px
。同理,如果显示窗口宽度为750px
,1vw
求得的值为7.5px
。vh
和vw
总是与视窗的高度和宽度有关,与之不同的,vmin
和vmax
是与视窗宽度和高度的最大值或最小值有关,取决于哪个更大和更小。例如,如果浏览器设置为1100px
宽、700px
高,1vmin
会是7px
,1vmax
为11px
。然而,如果宽度设置为800px
,高度设置为1080px
,1vmin
将会等于8px
而1vmax
将会是10.8px
。
同样的,现代 CSS 同样为视窗相对单位新增了一些新的单位。随着 CSS 逻辑属性的出现,视窗单位新增了 vi
和 vb
:
-
vi
:指浏览器视窗内联轴尺寸(inline-size
)的1%
-
vb
:指浏览器视窗块轴尺寸(block-size
)的1%
在 CSS 中使用 lv
前缀来定义大视窗的单位,其包含了 lvw
、lvh
、lvi
、lvb
、lvmin
和 lvmax
等单位。另外使用 sv
前缀来定义小视窗的单位,其包含了 svw
、svh
、svi
、svb
、svmin
和 svmax
等单位。动态视窗单位以 dv
前缀定义,其中包括 dvw
、dvh
、dvi
、dvb
、dvmin
和 dvmax
。
如果你对这些新增的 CSS 单位感兴趣的话,请移步阅读《现代 CSS》的 《现代 CSS 中的相对单位》课程中的视窗相对单位!
容器相对单位
CSS 规范目前主要定义了以下几种容器查询单位:
-
cqw
:查询宽度,相对于查询容器宽度计算,即1cqw
等于查询容器宽度的1%
-
cqh
:查询高度,相寻于查询容器高度计算,即1cqh
等于查询容器高度的1%
-
cqi
:查询内联轴尺寸,相对于查询容器内联轴尺寸计算,即1cqi
等于查询容器内联轴尺寸的1%
-
cqb
:查询块轴尺寸,相对于查询容器块轴尺寸计算,即1cqb
等于查询容器块轴尺寸的1%
-
cqmin
:查询最小值,是查询内联轴尺寸cqi
或查询块轴尺寸cqb
中较小的那个值 -
cqmax
:查询最大值,是查询内联轴尺寸cqi
或查询块轴尺寸cqb
中较大的那个值
角度单位
说到角度单位,事实上大家说到的更是度数单位,有关于这方面的单位,我们可能从生活中了解了很多关于他们相关的知识。在学校里学习几何课,做基本的木工活,进入外层空间或在图像编辑软件中旋转一个元素等,都会有角度相关的身影。
在现实世界中,度数几乎是测量角度的单位。它在 Web 中同样是一个受欢迎的角色,也适用于我们将遇到的各种场景。幸运的是,在现实世界中的度数和虚拟世界中的度数有很多相似之处。
在我们开始查看代码片段以及如何在 HTML、CSS 和 JavaScript 中使用度数单位之前,我们花一点点时间来回忆一下什么是度数,并介绍一些关于度数的基本概念。首先,也是最重要的是:
或许在这之前你可以看到过类似这样的一个图(其实就是一个圆)。它代表一个完整的旋转以及所有我们想要测量或指定的角度。需要记住一个大细节是:一个完整的旋转是由 360
度组成的 。所有的角度都会在0
至360
度之间:
这并不意味着你不能处理超出0
和360
范围的度数值。负数和大于360
度的值都是允许的。只是它们总是被归到0
和360
度范围内。看看下面两个标准化下变体:
在第一个变体中,我们指定的值实际上是-90
度。得到的角度路径是顺时针的,并停止在270
度(360 - 90 = 270
)位置处。在第二个变体中,我们指定的值是420
度。这意味着我们要做完一个完整的旋转(360
度),然后继续旋转60
度。在大多数情况下,第一个变体的最终度数值是270
度,第二个变体的最终度数值是60
度。角度的值是否为负值,并无关紧要。为了得到0
至360
之间的最终角度值,旋转的次数也不重要。同样,这只适用于大多数情况。在某些情况下,比如涉及到动画的情况下,我们采用最终角度度数值是非常重要的。我们稍后会谈到这个。
上面是有关于角度单位的基础理论的知识点。事实上,在 CSS 上也有很多有关于角度的使用场景。
CSS 中的旋转
角度最常用的用法之一就是在 CSS 中给旋转元素设置一个旋转角度(度数),依赖于 CSS 的transform
属性中的rotate()
,skew()
函数等。其中给rotate()
函数传一个角度的值,让元素做相应的旋转。比如:
css
.rectangle {
width: 200px;
height: 100px;
border: 10px solid #83B692;
background-color: #BEE7B8;
margin: 100px;
transform: rotate(37deg);
}
给rotate()
函数设置了一个37deg
的值,告诉元素.rectangle
围绕着旋转原点(旋转原点可以通过transform-origin
属性进行设置)旋转37deg
。最终这个.rectangle
元素旋转后的效果如下图所示:
看到这样的旋转结果,你是不是感到有点奇怪?37
度旋转出来的效果应该像下面这样才对,是吧?
我们在浏览器中看到的效果几乎与此相反。原因是与 Web 上定义旋转的方向有关系。在现实中,角度值是随着逆时针方向增加(在前面有提到过)。在 Web 上,角度值却是随着顺时针方向增加。
这似乎看上去有点奇怪,但事实就是这样,我们也无法改变。我们所要做的就是 记住这样的差异性,并在实际使用的时候做相应的调整。
有关于 CSS 中旋转运用到的角度值,介绍到这也就差不多了。但有一点需要记住,之前我们介绍过,如果角度值低于 0
或者大于 360
度最终都会规化到 0
至 360
度范围内 。大多数情况之下,负值和大于360
度值都并不很重要。下图就很好的阐述了负值和大于360
度值并不影响元素最终的旋转结果:
就上图的结果来看,.rectangle
元素旋转37deg
、397deg
、757deg
或-323deg
,其最终的结果都将是一样的。
只有当我们在做动画的时候,这个结果才不是一样的。在动画制作过程中,旋转角度的最终值和如何获得最终旋转的角度值都非常重要。这是制作动画的一个细节问题。对于负值,表示我们的元素在做逆时针旋转,旋转到最张的角度值;大于360deg
表示元素一直在旋转,直到最终的角度值。当我们真正的可视化实际发生的一切时,这样做的一切都变得有意义了。
下图的效果就是四个矩形旋转的另一个版本。从0
度开始旋转,一直旋转到最终值(37
、397
、757
和-323
度):
对于旋转37deg
的矩形动画没有什么特别之处,因为它是一个很正常的效果。对于旋转397deg
的矩形,它最终停止的点也是在37deg
的位置,只不过矩形做了一个完整(圆)的旋转之后,再继续旋转了37deg
(360 + 37
);757deg
度的这个矩形同样的,动画最终停止的位置也是37deg
那,只不过他做了两圈旋转之后,再继续旋转了37
度(360 + 360 + 37
);最后旋转-323deg
的矩形有点不一样,它是逆时针旋转,但最终动画停止位置也和其他矩形一样,是在37deg
位置处。所以,这四个矩形动画最终停止的位置是相同的,但动画如何到达停止处是完全不同的。
另外,这个动画的持续时间都是8s
(animation-duration: 8s
),这意味着四个矩形完成动画的时间都是8s
。那么问题来了,四个矩形旋转的角度不同(前提也提到过了,有的旋转一圈多,有的旋转两圈多),但动画持续时间都相同(都是8s
),而且他们要到达的目的地都是相同的(都是37deg
位置处),这样一来就会造成矩形旋转快慢的不同。正如在示例中看到的效果一样。
如果你对 Web 动画制作感兴趣,可以移步阅读《Web 动画之旅》,它是一本关于 Web 动画制作的系列教程!
上面我们主要讨论了 CSS 中旋转的角度是如何工作的,特别是在动画的中旋转角度值和平时有何不同的细节。接下来我们换过另一个话题继续聊 Web 中的度数(角度值)。
CSS 渐变中的角度
在 CSS 中还会使用到角度的另外一个典型属性是CSS 渐变的相关属性。比如线性渐变属性linear-gradient()
:
css
background: linear-gradient(45deg, #f36, #389);
上面代码中的45deg
指的是渐变的角度。很多同学会误以为渐变中的角度和旋转的角度应该是同一回事。事实上,他们是不一样的,如果你使用过类似 Photoshop 这样的编辑图片的软件,你可能会找到一定的答案:
从上图中可以看出来,渐变的角度和旋转的角度完全不是一回事。线性渐变的这个角度以圆心为起点发散。先来看一张图:
C
点是渐变容器的中心点(即,元素的中心点),A
点是通过C
点垂直线与通过C
点渐变线的夹角,这个角称为渐变角度 (比如示例中的45deg
)。在 CSS 的渐变属性中可以通过下面两种方法来定义这个角度:
-
使用关键词:
to top
、to bottom
、to left
、to right
、to top right
、to top left
、to bottom right
和to bottom left
-
使用带单位数字定义角度,比如
45deg
、1turn
等 (有关于deg
和turn
的关系,我们后续会说到)
如果省略角度值的设置,那默认是to bottom
(对应180deg
或者.5turn
):
在上面的示例中,渐变角度是没有设置,white
至red
渐变色从top
至bottom
渐变,它和使用to bottom
关键词得到的效果是一样的,如下所示:
除了使用这些关键词之外,还可以使用明确的角度值,比如45deg
,而且更建议你使用角度值来替代关键词。下图能帮助我们看看渐变角度动态变化时,渐变线是怎么移动的:
回顾一下渐变角度:
-
角度是渐变线与渐变容器中心点向上垂直线之间的夹角
-
0deg
的意思就是to top
-
角度的默认值(也就是角度没有设置),它的值是
to bottom
,也和180deg
相同 -
顶角关键词和渐变容器尺寸有关
其实 CSS 渐变是一个复杂的知识体系,这里面有很多不为人知的一面,如果你想深入了解这些潜在的坑,请移步阅读《防御式 CSS 精讲》中的《你不知道的 CSS 渐变》!
Canvas 中的角度
大家都知道,canvas
可以用来帮助我们绘制一些几何图形,也可以帮助我们做很多 CSS 之类无法做到的事情。在canvas
的部分 API 中也会使用到角度,比如使用arc()
、arcTo()
绘制圆和圆弧以及 Canvas 中的rotate()
方法。
在 Canvas 中,角度的测量和我们常见的角度测量是有所差异的,其差异如下图所示:
然而,在 Canvas 中,角度并不是我们通常意义上所了解的角度,而是用弧度来表示的。比如,一个圆是360
度,那么用弧度来表示的,其对应的就是2π
弧度,即以圆心为坐标原点,开始计算开始弧度与终止弧度。顺时针还是逆时针就是画线的方向(或者旋转方向),比如像下图这样:
对于很多 Web 开发者而言,大家更为熟知的是度数来表达角度,所以说,要在canvas
中使用度数,那还需要做一步转化过程,把度数转换成弧度。不过有关于度数转弧度,我们在后面会简单的介绍。
HSL 中的角度
在 CSS 中,我们有多种指定颜色的方式,最为经典的是十六进制和RGB
格式。除此之外,我们还可以使用另一种指定颜色的格式,即HSL
。其中HSL
分别是色相(Hue
),饱和度(Saturation
)和亮度(Lightness
)三个单词的首字母。
对于HSL
相关的细节已经超出这篇文章的有关范围,但维基百科上的HSL和HSV文章很好地解释了它的工作原理和目的。我们所知道的是,在 Web 中可以通过hsl
或hsla
函数来指定 HSL
格式中的任何颜色,这两个数都类似,唯一的区别是hsla
增加了对透明度的支持。比如,我们可以像下面这样使用hsla
来指定颜色:
css
background-color: hsla(54, 100%, 62%, 1);
上面使用hsla
指定了background-color
的值,上面的代码hsla(54, 100%, 62%, 1)
是一个黄橙色。
此时,你可能会感到纳闷。我们要聊的是 Web 中的角度相关的话题,那怎么又聊 Web 中的颜色呢?换句话说,HSL格式指定颜色与使用度数有何关系?如果你真的是这么想的,那表示你是对的,就应该这么的问。HSL
颜色(以及hsla
函数的扩展)是由四个值组成:色相 ,饱和度 ,亮度 和透明度。
HSL
中的H
,也就是颜色的色相,它指定色相的方式是以度数为单位的,这些度数映射到色盘上的颜色,比如像下图这样:
在我们这个示例中,指定的颜色的色相值是54
度。对应到色盘上的位置,就是我们看到的黄橙色。在实际使用的时候,如果一时无法确定角度值对应色盘上的颜色,我们可以借助浏览器开发者工具来帮助我们,比如像下面这样:
如果你想更进一步了解 CSS 颜色相关的知识,建议你移步阅读下面这些教程:
其他度数单位
前面我们大部分聊的都是角度单位,其实除了角度单位,我们还有百分度(grad
)、弧度(rad
)和圈数(turn
)单位:
-
百分度(
grads
) :一个分度,或者说是百分度相对于1/400
个整圆,跟角度单位一样,支持负值,负值表示逆时针方向,其中100grad
相当于90deg
-
弧度(
rad
) :在 Canvas 部分简单提到过弧度,1rad
等于180/π
度(大约为57.3deg
),另外1.570796326794897rad
相当于100grad
或是90deg
-
圈数(
turn
) :1turn
等于360deg
弧度和度数间转换
在前面,我们在 CSS 中大部分情况使用的是角度值都是用度数(deg
)来做为单位值,事实上也可以像在 JavaScript 中使用弧度rad
做为单位值。
正如大家所了解的一样。一个完整的圆的弧度是2π
,所以2π rad = 360°
,1 π rad = 180°
,1°= π/180 rad
,1 rad = 180°/π
(约57.29577951°
)。以度数表示的角度,把数字乘以π/180
便转换成弧度;以弧度表示的角度,乘以180/π
便转换成度数。
ini
rad = (π / 180) * deg
同样的:
ini
deg = (rad * 180) / π
平时我们常看到的各种弧度如下:
上面简单的介绍了度数和弧度之间的关系。其实在 JavaScript 中我们可以很容易实现度数和弧度之间的换数:
ini
rad = (Math.PI * deg) / 180
同样的:
ini
deg = (rad * 180) / Math.PI
为了方便计算和使用,可以将其封装成 JavaScript 函数:
javascript
function getRads (degrees) {
return (Math.PI * degrees) / 180;
}
function getDegrees (rads) {
return (rads * 180) / Math.PI;
}
比如我们要将30deg
转换成rad
,可以直接使用:
scss
getRads(30); // => 0.5235987755982988rad
getDegrees(0.7853981633974483); // => 45deg
下图展示了常见的角度和弧度之间的换算:
百分比单位
CSS 中百分比%
单位也是一个很重要也是很常用的单位,和px
、em
类似,在 CSS 中接受<length>
值的属性都可以使用%
单位。但在不同的使用场合,其意义将会有很多地不同。正因如此,要理解%
这个单位,其关键点是:百分比是一定要有其对应的参照值 ,也就是说,百分比值是一种相对值,任何时候要分析它的计算值,都需要正确的找到它的参照值。
言外之意,CSS 中的百分比单值最终计算出来的值是可变的。常见的可以分为以下几个大类:
定位中的百分比
在 CSS 中用来控制position
位置的top
、right
、bottom
和left
都可以使用百分比作为单位。如果它们的值为百分比时,其对应的参照物是包含块(但不一定是其父容器)同方向的width
或height
计算。
刚才提到过,定位属性中的参照物:包含块并不一定是其父容器 。为什么这么说呢?因为在 CSS 中position
对应的属性值不一样,其对应的包含块也将不同:
-
如果元素为静态(
static
)或相对定位(relative
),包含块一般是其父容器 -
如果元素为绝对定位(
absolute
),包含块应该是离它最近的position
为absolute
、relative
或fixed
的祖先元素 -
如果元素为固定定位(
fixed
),包含块就是视窗(viewport
)
盒 模型中的百分比
CSS 中的盒模型对应的属性主要有height
、min/max-height
、width
、min/max-height
、padding
、margin
和border
等属性。不同的属性其对应的参照物也有所不同。
-
height、min/max-height
属性的值为百分比时,其相对于包含块的height
进行计算 -
width、min/max-width
属性的值为百分比时,其相对于包含块的width
进行计算 -
padding
和margin
相对来说更为复杂一些,如果书写模式是水平的,则相对于包含块的width
进行计算;如果书写模式是垂直的,则相对于包含块的height
进行计算
文本中的百分比
在 CSS 中控制文本的属性常见的有font-size
、line-height
、text-indent
、vertical-align
等。不同的属性其参照物也是有所不同:
-
font-size
是基于父元素中font-size
进行计算 -
text-align
和padding
有点类似,和书写模式有一定的关系。如果书写模式是水平的,则相对于width
进行计算,如果是垂直的,则相对于height
进行计算 -
line-height
则基于font-size
进行计算 -
vertical-algin
则基于line-height
计算
边框和圆角中的百分比
在 CSS 中border-width
属性是不支持%单位的,但在border-radius
和border-image-width
两个属性上是可以使用百分比为单位的。如果在border-radius
中使用百分比单位,也就是说圆角的半径是通过百分比来进行计算的,即:水平方向的半径是相对于元素 width
计算,垂直方向的 半径是相对于元素高度进行计算。比如:
css
.circle{
width: 200px;
height: 200px;
border-radius:50%;
}
.ellipse {
width: 200px;
height: 100px;
border-radius: 50%;
}
上面的代码对应的结果如下图所示:
从结果是可以看出来,元素.circle
的width
和height
都是200px
,当border-radius: 50%
时,计算出来的值都是100px
;而.ellipse
元素的width
和height
分别是200px
和100px
,当border-radius
为50%
时,其计算出来的结果相当于border-radius: 100px / 50px
(水平方向相对于width
计算,垂直方向相对于height
计算)。
对于border-image-width
来说,相对要简单一些,如果该属性的值是百分比,其计算参照于图像边框区域的大小(包含border
和padding
)进行计算。
有关于圆角
border-radius
更详细的介绍,可以移步阅读《你不知道的 border-radius》!
背景属性中的百分比
在背景属性中,background-size
、background-origin
和background-position
属性都可以使用百分比作为单位。其中background-size
则是基于background-origin
区域的大小进行计算。可以对背景图像进行缩放处理。
对于background-position
中的百分比,相对而言更为复杂一些,需要通过一些数学公式计算:
(容器尺寸 - 背景图像尺寸)* 百分比值
当背景图片尺寸(background-size
)不做任何的重置(也就是100% 100%
)时,水平百分比的值等于容器宽度百分比值减去背景图片宽度百分比值。垂直百分比的值等于容器高度百分比值减去背景图片高度百分比值。
假设有一个元素,其width
是410px
,height
是210px
,使用的背景图片的尺寸是100px * 100px
。如果,background-position
的值是75% 50%
,那么百分比最终计算出来的值是:
-
水平位置(
x
轴):(410 - 100) * 75% = 232.5px
-
垂直位置(
y
轴):(210 - 100) * 50% = 55px
如果你的背景图片是通过渐变属性来绘制的话,那么在渐变中的每个颜色的位置也可以使用百分比来设置。对于这部分的计算相对而言细节更多,在这里不做过多的阐述,详细的介绍放到渐变那个章节来介绍。这个只提供一个简单的示例:
arduino
background-image: linear-gradient(80deg, red, blue, red, blue, red)
如果没有显式指定颜色在渐变线上的位置,这将交给浏览器来确定颜色在渐变线上的位置。最简单的情况下只有两个颜色,颜色1
将被放置在渐变线0%
位置(渐变线开始位置),颜色2
将被放置在100%
位置处(渐变线的结束点)。如果有三个颜色,那么颜色1
在渐变线的0%
,颜色2
在渐变线的50%
,颜色3
在渐变线的100%
。在上面的这个示例中,有五个颜色,那么它们的位置分别在0%
、25%
、50%
、75%
和100%
。它们将沿着渐变线平均分布渐变颜色。
在渐变中的百分比的计算是相对于渐变线计算。
变换中的百分比
CSS 中的transform
属性中的translate
和transform-origin
值也可以设置百分比。
-
translateX()
的百分比相对于容器的width
计算 -
translateY()
的百分比相对于容器的height
计算 -
transform-origin
中横坐标(x
)相对于容器的width
计算;纵坐标(y
)相对于容器的height
计算
注意,在
translate
还有一个z
轴的函数translateZ()
。它是不接受百分比为单位的值。
百分比值的继承
请注意,当百分比值用于可继承属性时,只有结合参照值计算后的绝对值会被继承,而不是百分比值本身 。例如,一个元素的font-size
是14px
,并定义了line-height:150%;
,那么该元素的下一级子元素继承到的line-height
就是21px
,而不会再和子元素自己的font-size
有关。
时间单位
CSS 中有两个常见的时间单位,即秒(s
)和毫秒(ms
)。其中1s = 1000ms
。这两个单位常用于 CSS 中transition-duration
、transition-delay
、animation-duration
和animation-delay
属性中。
频率单位
频率值使用在听(或说)级联样式表中,有两个单位值,及赫兹(Hz
)和千赫(kHz
),有点毫秒和秒的感觉。频率可以被用来改变一个语音阅读文本的音调。低频率是低音,高频率,高音。例如下面的代码:
css
.low {
pitch: 105Hz;
}
.squeal {
pitch: 135Hz;
}
小结
在 CSS 中,除了上述提到的单位,其实还有很多其他的 CSS 单位。这里只向大家介绍了一些常见或者常用的 CSS 单位。不管是相对单位,还是绝对单位,或者说时间、角度单位,我们都应该根据自己业务的场景来选择适合的单位。比如说在移动端做适配,可以选择视窗单位来做适配,如果扩展模块大小,可以使用em
来更为适合。对于其他的 CSS 单位,如果大家感兴趣的话,可以一一尝试。
如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程: