图说 CSS:CSS 的值和单位

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> ,用于指定例如元素 widthborder-widthfont-size 等属性的值,这些值可能带有单位,也可能不带任何单位
  • 百分比 :可以用于指定尺寸或长度,例如取决于父容器的 widthheight 或默认的 font-size
  • 颜色 :用于指定 background-colorcolor
  • 坐标位置 :以屏幕的左上角为坐标原点定位元素的位置,比如常见的 background-positiontoprightbottomleft 等属性
  • 函数 :用于指定背景图片或背景图片的渐变,比如 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 中有些单位是绝对值,不受任何屏幕大小或字体的影响。这些单位的显示可能会根据不同的屏幕分辨率而有所不同,因为它们取决于屏幕的 DPI(每英寸上的点数)。绝对单位常用于一些物理测量上。在环境输出已知的情形下非常有用。在 CSS 中,绝对单位包括: pxincmmmpcpt 等。其中 px 是我们最为常见的一个绝对单位。到目前为止, px 在 CSS 的使用中也可以算是主流单位之一。

像素单位被认为是许多其他单位的测量基础。它提供了各种设备中一致的结果。也被认为是最好的 设备像素 ,而这种像素长度和你在显示器上看到的文字屏幕像素元关。因为 px 实际上是一个按角度度量的单位,即 像素角度

很多时候, 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 英寸,所以它的视角是:

(1/96)in / (28in * 2 * PI / 360deg) = 0.0213度。

由于 CSS 像素是一个视角单位,所以在真正实现时,为了方便基本都是根据设备像素换算的。浏览器根据硬件设备能够直接获取 CSS 像素。

简单介绍一下一臂之遥:我们在使用不同设备输出时,眼睛与设备输出的典型距离是不同的。比如电脑显示器,通常是一臂之距,而看书和纸张时(对应于打印机的设备输出),则通常会更近一些。看电视时则会更远,比如一般建议是电视机屏幕对角线的 2.53 倍长 —— 如果你是个 42 英寸彩电,那就差不多是 3 米远。

这样描述对于很多 CSSer 太过于理论,我们还是回到实际中了。比如说我在项目中有一个盒子元素,它的大小是宽高都是 150px ,那么我们在 CSS 中常常这么使用:

.box {
    width: 150px;
    height: 150px;
}

虽然说,像素应该是设备和显示器中显示趋于一致,但是他越来越不正确。那是因为,随站 Retina 屏的出现, dpr 不同(设备像素比),对像素和显示器显示会略有不同。比如下图所示:

正因如此,在移动端设计当中,大部分设计都采用 2 倍或 3 倍尺寸进行设计。

虽然说 px 是 CSS 最绝对单位中最常见,使用最频繁的一个单位。而事实上,CSS 中绝对单位不仅仅这一个,还有其他的绝对单位,比如 in (英寸)、 cm (厘米)、 mm (毫米)、 pcpt 等。其中, incmmm 可以和 px 直接进行换算:

1in = 96px
1cm = 37.8px
1mm = 3.78px

pcptin 有直接关系:

1in = 72pt
1in = 6pc

如果你希望 ptpc 直接和 px 进行换算的话,可以借助 in 为中间桥梁。比如:

  • 1in = 96px = 72pt ,那么 1px = 72 / 96 = 0.75pt
  • 1in = 96px = 6pc ,那么 1px = 6 / 96 = 0.0625pc

可以用一张简单的图来描述绝对单位之间的关系:

在规范中,绝对单位还有一个新单位,不怎么常见,即 Q 1Q 相当于 25mm 。它被用于印刷排版。

相对单位

相对单位和绝对单位有所不同,相对单位是相对于另一个长度的长度。使用相对单元的样式更容易离开一个输出环境并适应另一个环境。CSS 的相对单位主要分为两大类,其一是字体相对单位,会根据 font-size 进行计算;其二是视窗相对单位,相对于视窗大小来决定。

字体相对单位

字体相对单位主要有 emremexchcapiclhrlh 。其中 emremexch 是较为常见的字体相对单位。在这里我们也只会介绍这几个常见的单位。

em

起初排版度量时是基于当天字体大写字母 M 的尺寸的。当改变 font-family 时,它的尺寸不会发生任何改变,但是在改变 font-size 的大小时,它的尺寸就会发生变化。

在 CSS 中,如果没有任何 CSS 规则影响的前提之下, 1em 的长度是:

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 计算和转换的复杂度,比如:

pxem 之间的转换存有一定的公式在,如下:

1 ÷ 父元素的font-size × 需要转换的像素值 = em值

我们也可以借助于 JavaScript,写一个简单的转换函数:

function px2em(pixel,parentFontSize) {
    retrun (pixel / parentSize) + 'em'
}

px2em(10, 16) // => 0.625em

em 单位除了应用于 font-size 属性之外,还可以运用于可以使用 <length> 值的其他属性,比如 widthmarginpaddingborder-widthtext-shadow 等等。

<length> 是表示距离尺寸的一种 CSS 数据格式。它由一个 <number> 后紧随一个长度单位,比如 pxemptin 等等。和任何 CSS 尺寸一样,数字和单位之间没有空格。如果 <number>0 的话,其之后的长度单位是可选的。

如果在非 font-size 的属性上使用 em 做为 <length> 值的单位时,将会受元素 font-size 的影响。在众多开发者中有一个比较普遍的语解,认为 em 单位是相对于父元素的 font-size 。而事实上呢?它们是 相对于使用 em 单位元素的 font-size 。父元素的 font-size 可以影响 em 值,但这种情况的发生,纯粹是因为继承。

前面也提到过,使用 em 单位存在继承的时候,会让我们处理单位的转换时变得比较棘手。

为会要处理单位的转换呢?那是因为我们拿到的设计稿,其度量单位大多数是 px 为单位。如此一来,从设计稿转换到 Web 页面的时候,我们就存在 pxem 这样的一个过程。

从前面的知识中,我们得知,使用 em 单位的属性会根据元素 font-size 大小来决定。但该元素可能继承其父元素的 font-size ,而父元素又有可能继承其父元素的 font-size 。因此,以 em 为单位的 font-size 可能会受到其任何父元素的 font-size 大小影响。这个论点在上面的示例中已得到了验证。

既然元素 font-size 大小会有变化,那么该元素上使用 em 为单位的属性,也将会受到相应的影响。我们来看看相应的示例:

div {
    width: 20em;
    height: 20em;
    border: 1em solid;
    padding: 3em;
}

你看到的效果如下:

在这个示例中,我们没有在 div 元素和其祖先元素显式的设置 font-size ,所以该元素的 font-size 会继承浏览器的默认 font-size ,即 16px 。因此在 widthheightborder-widthpadding 属性中的 em 会根据 16px 做为基准进行计算。因此,最终得到的效果如上图所示。如果我们在 div 中嵌套一个子元素 div 。得到的效果将如下:

两个 div 使用 em 的属性,最终计算出来的结果是一样的,只不过子元素 div 溢出了父元素 div 。如果我们在子元素 div 中显式的设置 font-size: .5em ,得到的结果将是另外一种:

就此而言, em 单位可以更好的维护和扩展组件的大小。比如,控制组件大小的属性,比如 widthheightpaddingborder-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 属性上的运用,但 remem 有一个最大的区别: 任何值为 1rem 的元素都等于 16px ,当然,其前提是浏览器默认的 font-size 没有被用户重置,或者未显式的给 html 元素设置 font-size 值;另外, rem 可以不管它的父元素的 font-size 如何

从上图可以看出,就算是 body 中显式的设置了 font-size 的值,但其并不会影响其子元素 h3font-sizeh3font-size 始终都是相对于根元素 <html> 来计算的。

另外, remem 有点类似,能接受 <length> 为值的属性都可以以 rem 为单位,而且都是相对于根元素 htmlfont-size 进行计算,并且跟 DOM 的层级没有任何的关系。

em 还是 rem

在实际开发中,很多时候很多同学都会问:

em 好,还是 rem 好,应该选择哪个更好?

事实上,这是一个极具争议的一个问题。因为在实际中,一些开发人员完全避免使用 rem ,声称使用 rem 会使他们的组件缺少模块化;另外一些开发人员则什么都使用 rem ,因为喜欢 rem 所带来的便捷。那么应该更好的去选择呢:

没有最好的,只有最适合的!

对于是选择 rem 还是 em ,应该出于理智,在不同的地方使用 remem 。事实上,很多成功的案例也证明了这样的观点:

  • 如果这个属性根据它的 font-size 来进行测量,则应该选择 em
  • 其他的一切事物均应该使用 rem

同时,大家也可以根据两者的差异性来进行选择:

  • remem 在客户端中计算出来的样式值( 计算样式(Computed Style) )都会以 px 显式
  • rem 相对于根元素 htmlfont-size 计算, em 相对于元素 font-size 计算
  • rem 可以从浏览器字体设置中继承 font-size 值, em 可能受任何继承过来的父元素 font-size 的影响
  • 使用 em 应该根据组件的 font-size 来定,而不是根元素的 font-size 来定
  • 在不需要使用 em 单位,并且需要根据浏览器的 font-size 设置缩放时,应该使用 rem

exch

exch 是排版单位,这意味着它们的值取决于元素的 font-family 。而我们在使用 emrem 单位时,浏览器会根据元素的 font-size 计算它们的值。无论屏幕上显示的是什么字体,浏览器计算出来的值都是相同的。这就是 exch 单位提供更多灵活性的地方。它们要求浏览器在计算值和应用样式之前要确定好引用的 font-family 。因为,元素的 font-family 样式对 exch 单位值的计算有直接关系和影响。

在印刷术语中, x 高度由字体小写字母的高度决定。这通常用它母 x 来衡量,它没有任何上升和下降。字体的 font-sizex 高度之间的关系可以告诉你很多关于字体的比例。

ex 单位的值来自它们所计算的字体上下文的 x 高度, x 高度由两个因素决定: font-familyfont-size 。换句话说,它们等于特定字体在特定 font-size 下的 x 高。

正如上图, font-familyHelvetica Neue 设置的 font-size100px ,那么 1ex 大约等于 52px

chex 相似,但它不依赖于 x 的高度;而是基于字体的字符,从字体的 0 字形宽度中提取它们的值,它还随字体而变化。如此一来,就有点随意,而 0 的宽度通常是对字体的平均字符宽度,这是一个估计值,所以会有点糟糕。

由于 ch 单位是一个近似等宽的一个单元,因此在设置容器的宽度是特别的有用。比如说,你想让容器显示特定数量的字符串时,就可以使用 ch 单位。

视窗相对单位

CSS 中除了字体相对单位之外还有视窗相对单位,主要有 vwvhvminvmax 。在了解视窗单位之前,先简单的了解一下视窗的概念,这样有助于我们更好的理解视窗单位。

在 PC 端,视窗指的是浏览器的可视区域,而在移动端中相对来说更为复杂一些,它包括三个视窗: 布局视窗 (Layout Viewport)、 视觉视窗 (Visual Viewport)和 理想视窗 (Ideal Viewport):

而我们要说的视窗单位中的视窗指的是: PC 端指的是浏览器可视区域,移动端的是布局视窗(Layout Viewport)

有了视窗的概念,就可以更好的理解 CSS 中有关于视窗单位,在 CSS 中视窗单位主要有:

  • vw :视窗宽度的百分比
  • vh :视窗高度的百分比
  • vmin :当前较小的 vwvh
  • vmax :当前较大的 vwvh

用下图来描述,大家会更清晰一些:

简单的来看看视窗单位是如何进行计算的。例如,如果浏览器的高是 900px , 1vh 求得的值为 9px 。同理,如果显示窗口宽度为 750px , 1vw 求得的值为 7.5pxvhvw 总是与视窗的高度和宽度有关,与之不同的, vminvmax 是与视窗宽度和高度的最大值或最小值有关,取决于哪个更大和更小。例如,如果浏览器设置为 1100px 宽、 700px 高, 1vmin 会是 7px , 1vmax11px 。然而,如果宽度设置为 800px ,高度设置为 1080px1vmin 将会等于 8px1vmax 将会是 10.8px

角度单位

说到角度单位,事实上大家说到的更是度数单位,有关于这方面的单位,我们可能从生活中了解了很多关于他们相关的知识。在学校里学习几何课,做基本的木工活,进入外层空间或在图像编辑软件中旋转一个元素等,都会有角度相关的身影。

在现实世界中,度数几乎是测量角度的单位。它在 Web 中同样是一个受欢迎的角色,也适用于我们将遇到的各种场景。幸运的是,在现实世界中的度数和虚拟世界中的度数有很多相似之处。

在我们开始查看代码片段以及如何在 HTML、CSS 和 JavaScript 中使用度数单位之前,我们花一点点时间来回忆一下什么是度数,并介绍一些关于度数的基本概念。首先,也是最重要的是:

或许在这之前你可以看到过类似这样的一个图(其实就是一个圆)。它代表一个完整的旋转以及所有我们想要测量或指定的角度。需要记住一个大细节是: 一个完整的旋转是帽 360 度组成的 。所有的角度都会在 0360 度之间:

这并不意味着你不能处理超出 0360 范围的度数值。负数和大于 360 度的值都是允许的。只是它们总是被归到 0360 度范围内。看看下面两个标准化下变体:

在第一个变体中,我们指定的值实际上是 -90 度。得到的角度路径是顺时针的,并停止在 270 度( 360 - 90 = 270 )位置处。在第二个变体中,我们指定的值是 420 度。这意味着我们要做完一个完整的旋转( 360 度),然后继续旋转 60 度。在大多数情况下,第一个变体的最终度数值是 270 度,第二个变体的最终度数值是 60 度。角度的值是否为负值,并无关紧要。为了得到 0360 之间的最终角度值,旋转的次数也不重要。同样,这只适用于大多数情况。在某些情况下,比如涉及到动画的情况下,我们采用最终角度度数值是非常重要的。我们稍后会谈到这个。

上面是有关于角度单位的基础理论的知识点。事实上,在 CSS 上也有很多有关于角度的使用场景。

CSS 中的旋转

角度最常用的用法之一就是在 CSS 中给旋转元素设置一个旋转角度(度数),依赖于 CSS 的 transform 属性中的 rotate()skew() 函数等。其中给 rotate() 函数传一个角度的值,让元素做相应的旋转。比如:

.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 度最终都会规化到 0360 度范围内 。大多数情况之下,负值和大于 360 度值都并不很重要。下图就很好的阐述了负值和大于 360 度值并不影响元素最终的旋转结果:

就上图的结果来看, .rectangle 元素旋转 37deg397deg757deg-323deg ,其最终的结果都将是一样的。

只有当我们在做动画的时候,这个结果才不是一样的。在动画制作过程中,旋转角度的最终值和如何获得最终旋转的角度值都非常重要。这是制作动画的一个细节问题。对于负值,表示我们的元素在做逆时针旋转,旋转到最张的角度值;大于 360deg 表示元素一直在旋转,直到最终的角度值。当我们真正的可视化实际发生的一切时,这样做的一切都变得有意义了。

下图的效果就是四个矩形旋转的另一个版本。从 0 度开始旋转,一直旋转到最终值( 37397757-323 度):

对于旋转 37deg 的矩形动画没有什么特别之处,因为它是一个很正常的效果。对于旋转 397deg 的矩形,它最终停止的点也是在 37deg 的位置,只不过矩形做了一个完整(圆)的旋转之后,再继续旋转了 37deg360 + 37 ); 757deg 度的这个矩形同样的,动画最终停止的位置也是 37deg 那,只不过他做了两圈旋转之后,再继续旋转了 37 度( 360 + 360 + 37 );最后旋转 -323deg 的矩形有点不一样,它是逆时针旋转,但最终动画停止位置也和其他矩形一样,是在 37deg 位置处。所以,这四个矩形动画最终停止的位置是相同的,但动画如何到达停止处是完全不同的。

另外,这个动画的持续时间都是 8sanimation-duration: 8s ),这意味着四个矩形完成动画的时间都是 8s 。那么问题来了,四个矩形旋转的角度不同(前提也提到过了,有的旋转一圈多,有的旋转两圈多),但动画持续时间都相同(都是 8s ),而且他们要到达的目的地都是相同的(都是 37deg 位置处),这样一来就会造成矩形旋转快慢的不同。正如在示例中看到的效果一样。

上面我们主要讨论了 CSS 中旋转的角度是如何工作的,特别是在动画的中旋转角度值和平时有何不同的细节。接下来我们换过另一个话题继续聊 Web 中的度数(角度值)。

CSS 渐变中的角度

在 CSS 中还会使用到角度的另外一个典型属性是 CSS 渐变的相关属性。比如线性渐变属性 linear-gradient()

background: linear-gradient(45deg, #f36, #389);

上面代码中的 45deg 指的是渐变的角度。很多同学会误以为渐变中的角度和旋转的角度应该是同一回事。事实上,他们是不一样的,如果你使用过类似 Photoshop 这样的编辑图片的软件,你可能会找到一定的答案:

从上图中可以看出来,渐变的角度和旋转的角度完全不是一回事。线性渐变的这个角度以圆心为起点发散。先来看一张图:

C 点是渐变容器的中心点(即,元素的中心点), A 点是通过 C 点垂直线与通过 C 点渐变线的夹角,这个角称为 渐变角度 (比如示例中的 45deg )。在 CSS 的渐变属性中可以通过下面两种方法来定义这个角度:

  • 使用关键词: to topto bottomto leftto rightto top rightto top leftto bottom rightto bottom left
  • 使用带单位数字定义角度,比如 45deg1turn 等 (有关于 degturn 的关系,我们后续会说到)

如果省略角度值的设置,那默认是 to bottom (对应 180deg 或者 .5turn ):

在上面的示例中,渐变角度是没有设置, whitered 渐变色从 topbottom 渐变,它和使用 to bottom 关键词得到的效果是一样的,如下所示:

除了使用这些关键词之外,还可以使用明确的角度值,比如 45deg ,而且更建议你使用角度值来替代关键词。下图能帮助我们看看渐变角度动态变化时,渐变线是怎么移动的:

回顾一下渐变角度:

  • 角度是渐变线与渐变容器中心点向上垂直线之间的夹角
  • 0deg 的意思就是 to top
  • 角度的默认值(也就是角度没有设置),它的值是 to bottom ,也和 180deg 相同
  • 顶角关键词和渐变容器尺寸有关

Canvas 中的角度

大家都知道, canvas 可以用来帮助我们绘制一些几何图形,也可以帮助我们做很多 CSS 之类无法做到的事情。在 canvas 的部分 API 中也会使用到角度,比如使用 arc()arcTo() 绘制圆和圆弧以及 Canvas 中的 rotate() 方法。

在 Canvas 中,角度的测量和我们常见的角度测量是有所差异的,其差异如下图所示:

然而,在 Canvas 中,角度并不是我们通常意义上所了解的角度,而是用弧度来表示的。比如,一个圆是 360 度,那么用弧度来表示的,其对应的就是 弧度,即以圆心为坐标原点,开始计算开始弧度与终止弧度。顺时针还是逆时针就是画线的方向(或者旋转方向),比如像下图这样:

对于很多 Web 开发者而言,大家更为熟知的是度数来表达角度,所以说,要在 canvas 中使用度数,那还需要做一步转化过程,把度数转换成弧度。不过有关于度数转弧度,我们在后面会简单的介绍。

HSL 中的角度

在 CSS 中,我们有多种指定颜色的方式,最为经典的是十六进制和 RGB 格式。除此之外,我们还可以使用另一种指定颜色的格式,即 HSL 。其中 HSL 分别是色相( Hue ),饱和度( Saturation )和亮度( Lightness )三个单词的首字母。

对于 HSL 相关的细节已经超出这篇文章的有关范围,但 维基百科上的 HSLHSV 文章 很好地解释了它的工作原理和目的。我们所知道的是,在 Web 中可以通过 hslhsla 函数来指定 HSL 格式中的任何颜色,这两个数都类似,唯一的区别是 hsla 增加了对透明度的支持。比如,我们可以像下面这样使用 hsla 来指定颜色:

background-color: hsla(54, 100%, 62%, 1);

上面使用 hsla 指定了 background-color 的值,上面的代码 hsla(54, 100%, 62%, 1) 是一个黄橙色。

此时,你可能会感到纳闷。我们要聊的是 Web 中的角度相关的话题,那怎么又聊 Web 中的颜色呢?换句话说, HSL 格式指定颜色与使用度数有何关系?如果你真的是这么想的,那表示你是对的,就应该这么的问。 HSL 颜色(以及 hsla 函数的扩展)是由四个值组成: 色相饱和度亮度透明度

HSL 中的 H ,也就是颜色的色相,它指定色相的方式是 以度数为单位的,这些度数映射到色盘上的颜色 ,比如像下图这样:

在我们这个示例中,指定的颜色的色相值是 54 度。对应到色盘上的位置,就是我们看到的黄橙色。在实际使用的时候,如果一时无法确定角度值对应色盘上的颜色,我们可以借助浏览器开发者工具来帮助我们,比如像下面这样:

其他度数单位

前面我们大部分聊的都是角度单位,其实除了角度单位,我们还有百分度( grad )、弧度( rad )和圈数( turn )单位:

  • 百分度( grads :一个分度,或者说是百分度相对于 1/400 个整圆,跟角度单位一样,支持负值,负值表示逆时针方向,其中 100grad 相当于 90deg
  • 弧度( rad :在 Canvas 部分简单提到过弧度, 1rad 等于 180/π 度(大约为 57.3deg ),另外 1.570796326794897rad 相当于 100grad 或是 90deg
  • 圈数( turn1 圈等于 360deg

弧度和度数间转换

在前面,我们在 CSS 中大部分情况使用的是角度值都是用度数( deg )来做为单位值,事实上也可以像在 JavaScript 中使用弧度 rad 做为单位值。

正如大家所了解的一样。一个完整的圆的弧度是 ,所以 2π rad = 360°1 π rad = 180°1°= π/180 rad1 rad = 180°/π (约 57.29577951° )。以度数表示的角度,把数字乘以 π/180 便转换成弧度;以弧度表示的角度,乘以 180/π 便转换成度数。

rad = (π / 180) * deg

同样的:

deg = (rad * 180) / π

平时我们常看到的各种弧度如下:

上面简单的介绍了度数和弧度之间的关系。其实在 JavaScript 中我们可以很容易实现度数和弧度之间的换数:

rad = (Math.PI * deg) / 180

同样的:

deg = (rad * 180) / Math.PI

为了方便计算和使用,可以将其封装成 JavaScript 函数:

function getRads (degrees) {
    return (Math.PI * degrees) / 180;
}

function getDegrees (rads) {
    return (rads * 180) / Math.PI;
}

比如我们要将 30deg 转换成 rad ,可以直接使用:

getRads(30); // 0.5235987755982988rad
getDegrees(0.7853981633974483); // 45deg

下图展示了常见的角度和弧度之间的换算:

百分比单位

CSS 中百分比 % 单位也是一个很重要也是很常用的单位,和 pxem 类似,在 CSS 中接受 <length> 值的属性都可以使用 % 单位。但在不同的使用场合,其意义将会有很多地不同。正因如此,要理解 % 这个单位,其关键点是: 百分比是一定要有其对应的参照值 ,也就是说, 百分比值是一种相对值,任何时候要分析它的计算值,都需要正确的找到它的参照值

言外之意,CSS 中的百分比单值最终计算出来的值是可变的。常见的可以分为以下几个大类:

定位中的百分比

在 CSS 中用来控制 position 位置的 toprightbottomleft 都可以使用百分比作为单位。如果它们的值为百分比时,其对应的参照物是包含块(但不一定是其父容器)同方向的 widthheight 计算。

刚才提到过,定位属性中的参照物: 包含块并不一定是其父容器 。为什么这么说呢?因为在 CSS 中 position 对应的属性值不一样,其对应的包含块也将不同:

  • 如果元素为静态( static )或相对定位( relative ),包含块一般是其父容器
  • 如果元素为绝对定位( absolute ),包含块应该是离它最近的 positionabsoluterelativefixed 的祖先元素
  • 如果元素为固定定位( fixed ),包含块就是视窗( viewport

盒模型中的百分比

CSS 中的盒模型对应的属性主要有 heightmin/max-heightwidthmin/max-heightpaddingmarginborder 等属性。不同的属性其对应的参照物也有所不同。

  • heightmin/max-height 属性的值为百分比时,其相对于包含块的 height 进行计算
  • widthmin/max-width 属性的值为百分比时,其相对于包含块的 width 进行计算
  • paddingmargin 相对来说更为复杂一些,如果书写模式是水平的,则相对于包含块的 width 进行计算;如果书写模式是垂直的,则相对于包含块的 height 进行计算

文本中的百分比

在 CSS 中控制文本的属性常见的有 font-sizeline-heighttext-indentvertical-align 等。不同的属性其参照物也是有所不同:

  • font-size 是基于父元素中 font-size 进行计算
  • text-alignpadding 有点类似,和书写模式有一定的关系。如果书写模式是水平的,则相对于 width 进行计算,如果是垂直的,则相对于 height 进行计算
  • line-height 则基于 font-size 进行计算
  • vertical-algin 则基于 line-height 计算

边框和圆角中的百分比

在 CSS 中 border-width 属性是不支持 % 单位的 ,但在 border-radiusborder-image-width 两个属性上是可以使用百分比为单位的。如果在 border-radius 中使用百分比单位,也就是说圆角的半径是通过百分比来进行计算的,即: 水平方向的半径是相对于元素 width 计算,垂直方向的  半径是相对于元素高度进行计算 。比如:

.circle{
    width: 200px;
    height: 200px;
    border-radius:50%;
}

.ellipse {
    width: 200px;
    height: 100px;
    border-radius: 50%;
}

上面的代码对应的结果如下图所示:

从结果是可以看出来,元素 .circlewidthheight 都是 200px ,当 border-radius: 50% 时,计算出来的值都是 100px ;而 .ellipse 元素的 widthheight 分别是 200px100px ,当 border-radius50% 时,其计算出来的结果相当于 border-radius: 100px / 50px (水平方向相对于 width 计算,垂直方向相对于 height 计算)。

对于 border-image-width 来说,相对要简单一些,如果该属性的值是百分比,其计算参照于图像边框区域的大小(包含 borderpadding )进行计算。

背景属性中的百分比

在背景属性中, background-sizebackground-originbackground-position 属性都可以使用百分比作为单位。其中 background-size 则是基于 background-origin 区域的大小进行计算。可以对背景图像进行缩放处理。

对于 background-position 中的百分比,相对而言更为复杂一些,需要通过一些数学公式计算:

(容器尺寸 - 背景图像尺寸)* 百分比值

当背景图片尺寸( background-size )不做任何的重置(也就是 100% 100% )时,水平百分比的值等于容器宽度百分比值减去背景图片宽度百分比值。垂直百分比的值等于容器高度百分比值减去背景图片高度百分比值。

假设有一个元素,其 width410pxheight210px ,使用的背景图片的尺寸是 100px * 100px 。如果, background-position 的值是 75% 50% ,那么百分比最终计算出来的值是:

  • 水平位置( x 轴): (410 - 100) * 75% = 232.5px
  • 垂直位置( y 轴): (210 - 100) * 50% = 55px

如果你的背景图片是通过渐变属性来绘制的话,那么在渐变中的每个颜色的位置也可以使用百分比来设置。对于这部分的计算相对而言细节更多,在这里不做过多的阐述,详细的介绍放到渐变那个章节来介绍。这个只提供一个简单的示例:

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 属性中的 translatetransform-origin 值也可以设置百分比。

  • translateX() 的百分比相对于容器的 width 计算
  • translateY() 的百分比相对于容器的 height 计算
  • transform-origin 中横坐标( x )相对于容器的 width 计算;纵坐标( y )相对于容器的 height 计算

注意,在 translate 还有一个 z 轴的函数 translateZ() 。它是不接受百分比为单位的值。

百分比值的继承

请注意, 当百分比值用于可继承属性时,只有结合参照值计算后的绝对值会被继承,而不是百分比值本身 。例如,一个元素的 font-size14px ,并定义了 line-height:150%; ,那么该元素的下一级子元素继承到的 line-height 就是 21px ,而不会再和子元素自己的 font-size 有关。

时间单位

CSS 中有两个常见的时间单位,即 s )和 毫秒ms )。其中 1s = 1000ms 。这两个单位常用于 CSS 中 transition-durationtransition-delayanimation-durationanimation-delay 属性中。

频率单位

频率值使用在听(或说)级联样式表中,有两个单位值,及 赫兹Hz )和 千赫kHz ),有点毫秒和秒的感觉。频率可以被用来改变一个语音阅读文本的音调。低频率是低音,高频率,高音。例如下面的代码:

.low {
    pitch: 105Hz;
}
.squeal {
    pitch: 135Hz;
}

总结

在 CSS 中,除了上述提到的单位,其实还有很多其他的 CSS 单位。这里只向大家介绍了一些常见或者常用的 CSS 单位。不管是相对单位,还是绝对单位,或者说时间、角度单位,我们都应该根据自己业务的场景来选择适合的单位。比如说在移动端做适配,可以选择视窗单位来做适配,如果扩展模块大小,可以使用 em 来更为适合。对于其他的 CSS 单位,如果大家感兴趣的话,可以一一尝试。或者大家在这方面有更好的理解或使用经验,也欢迎在下面的评论中与我们一起分享。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章