图解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 相对长度单位主要分为字体相对长度单位视窗相对长度单位容器查询相对长度单位三种:

  • 字体相对长度单位:指的是使用它们的元素(用于本地字体相对长度)或根元素(用于根字体相对长度)的字体度量

  • 视窗相对长度单位 :相对于浏览器视窗的尺寸的长度,例如 vwvh

  • 容器查询相对长度单位 :相对于查询容器的尺寸的长度,例如 cqwcqh

那么在这篇文章中,我们主要围绕着 CSS 中常用单位来展开。介绍这些 CSS 单位使用的场景和使用细节。

绝对单位

在 CSS 中有些单位是绝对值,不受任何屏幕大小或字体的影响。这些单位的显示可能会根据不同的屏幕分辨率而有所不同,因为它们取决于屏幕的 DPI(每英寸上的点数)。绝对单位常用于一些物理测量上。在环境输出已知的情形下非常有用。在 CSS 中,绝对单位包括:pxincmmmpcpt等。其中px是我们最为常见的一个绝对单位。到目前为止,px在 CSS 的使用中也可以算是主流单位之一。

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

有关于设备像素更多的介绍,请移步阅读《现代 Web 布局》的《下一代响应式 Web 设计:组件驱动式 Web 设计》。

很多时候,px 也常被称为 CSS 像素。它是一个绝对单位,但也可以被视为相对单位,为什么这么说呢?那是因为像素单位相对的是设备像素。在同一样的设备上,每1个 CSS 像素所代表的物理像素是可以变化的(即 CSS 像素的第一方面的相对性);在不同的设备之间,每1个 CSS 像素所代表的物理像素是可以变化的(即 CSS 像素的第二方面的相对性)。

根据维基百科的解释:

它是图像显示的基本单元,既不是一个确定的物理量,也不是一个点或者小方块,而是一个抽象概念。所以在谈论像素时一定要清楚它的上下文!

不同的设备,图像基本采样的单元是不同的,显示器上的物理像素等于显示器的点距,而打印机的物理像素等于打印机的墨点。而衡量点距大小和打印机墨点大小的单位分别被称为PPIDPI

由于不同的物理设备的物理像素的大小是不一样的,所以 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.53倍长 ------ 如果你是个42英寸彩电,那就差不多是3米远。

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

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

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

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

相对单位

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

字体相对单位

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

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

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

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>值的其他属性,比如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为单位的属性,也将会受到相应的影响。我们来看看相应的示例:

css 复制代码
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

ex和ch

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

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

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

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

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

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

现代 CSS》的 《现代 CSS 中的相对单位》所述,现代 CSS 中字体相对单位,除了上现提到的单位之外,还有其他一些字体相对单位:

  • rex :相对于根元素上的 ex 单位的值计算

  • rch :相对于根元素上的 ch 单位的值计算

  • cap :等于第一个可用字体的使用帽高度(cap-height),它大约等于大写拉丁字母的高度

  • rcap :相对于根元素上的 cap 单位的值计算

  • lh :等于元素的行高(line-height

  • rlh :相对于根元素上的 lh 单位的值计算,当用于根元素的 font-sizeline-height 属性时,它指的是这些属性的初始值

  • ic :是 ch 的东方版本。它是 CJK (中文、日文和韩文)表意文字 U+6C34)的大小,因此可以粗略地解释为"表意文字计数"。在不可能或不实际确定表意文字的大小情况下,必须假定为 1em

  • ric :相对于根元素上的 ic 单位的值计算

视窗相对单位

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

同样的,现代 CSS 同样为视窗相对单位新增了一些新的单位。随着 CSS 逻辑属性的出现,视窗单位新增了 vivb

  • vi :指浏览器视窗内联轴尺寸(inline-size)的 1%

  • vb :指浏览器视窗块轴尺寸(block-size)的 1%

在 CSS 中使用 lv 前缀来定义大视窗的单位,其包含了 lvwlvhlvilvblvminlvmax 等单位。另外使用 sv 前缀来定义小视窗的单位,其包含了 svwsvhsvisvbsvminsvmax 等单位。动态视窗单位以 dv 前缀定义,其中包括 dvwdvhdvidvbdvmindvmax

如果你对这些新增的 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 度组成的 。所有的角度都会在0360度之间:

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

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

上面是有关于角度单位的基础理论的知识点。事实上,在 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元素旋转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位置处),这样一来就会造成矩形旋转快慢的不同。正如在示例中看到的效果一样。

如果你对 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 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相同

  • 顶角关键词和渐变容器尺寸有关

其实 CSS 渐变是一个复杂的知识体系,这里面有很多不为人知的一面,如果你想深入了解这些潜在的坑,请移步阅读《防御式 CSS 精讲》中的《你不知道的 CSS 渐变》!

Canvas 中的角度

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

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

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

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

HSL 中的角度

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

对于HSL相关的细节已经超出这篇文章的有关范围,但维基百科上的HSL和HSV文章很好地解释了它的工作原理和目的。我们所知道的是,在 Web 中可以通过hslhsla函数来指定 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π rad = 360°1 π rad = 180°1°= π/180 rad1 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 中百分比%单位也是一个很重要也是很常用的单位,和pxem类似,在 CSS 中接受<length>值的属性都可以使用%单位。但在不同的使用场合,其意义将会有很多地不同。正因如此,要理解%这个单位,其关键点是:百分比是一定要有其对应的参照值 ,也就是说,百分比值是一种相对值,任何时候要分析它的计算值,都需要正确的找到它的参照值

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

定位中的百分比

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

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

  • 如果元素为静态(static)或相对定位(relative),包含块一般是其父容器

  • 如果元素为绝对定位(absolute),包含块应该是离它最近的positionabsoluterelativefixed的祖先元素

  • 如果元素为固定定位(fixed),包含块就是视窗(viewport

模型中的百分比

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

  • height、min/max-height属性的值为百分比时,其相对于包含块的height进行计算

  • width、min/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 计算,垂直方向的 半径是相对于元素高度进行计算。比如:

css 复制代码
.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)进行计算。

有关于圆角 border-radius 更详细的介绍,可以移步阅读《你不知道的 border-radius》!

背景属性中的百分比

在背景属性中,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

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

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属性中的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),有点毫秒和秒的感觉。频率可以被用来改变一个语音阅读文本的音调。低频率是低音,高频率,高音。例如下面的代码:

css 复制代码
.low {
    pitch: 105Hz;
}
.squeal {
    pitch: 135Hz;
}

小结

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


如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程:

相关推荐
我要洋人死23 分钟前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人34 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人35 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR40 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香42 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#