Skip to content
This page has been auto-translated and may contain errors.View in English

尺寸和单位

docs.scrimba.com

你用像素设置字体大小,发布页面,然后一个为了舒适而增加浏览器文本大小的用户看到完全没有变化。你给一张卡片设置固定宽度,它在手机上溢出。两者都归结为同一个问题:当你在 CSS 中输入一个数字时,该数字相对于什么来测量?有些单位是固定的,有些缩放到字体,有些缩放到父元素,有些缩放到屏幕。一旦你知道哪个是哪个,你就会停止猜测,开始选择能完成工作的单位。

绝对单位 vs 相对单位

CSS 单位分为两个家族。一个**绝对单位**是永远不变的固定大小:px(像素)是你随处可见的单位。相对单位是缩放到其他东西的大小,比如读者的字体大小或屏幕宽度。

想象测量一个房间。厘米是绝对的:一面墙是 400 厘米,无论你是高还是矮。"我走三步"是相对的:这取决于谁在走。绝对单位给你精确的控制;相对单位让页面适应看它的人。

这种适应很重要。一些读者设置了更大的默认文本大小,因为这对他们的眼睛更容易。如果你用相对单位调整文本大小,他们的设置会传递下来,页面会增长以适应他们。如果你用像素锁定它,它会保持不变并忽略他们。

CSS 中的每个长度都是绝对的或相对的,差异决定了你的布局是否能适应。一个**绝对单位**无论上下文如何都解析为固定大小:px 是实际上你会使用的唯一绝对单位,因为 cmpt 和其他的都是为印刷设计的。相对单位相对于一个参考来解析,参考是什么取决于单位:remem 缩放到字体大小,% 缩放到父元素,vwvh 缩放到视口。

更倾向于使用相对单位进行大多数尺寸设置的原因是可访问性和响应式设计。当读者提高浏览器的默认字体大小时,用 rem 调整大小的任何东西都会随之增长,而用像素固定的任何东西都会保持不变并可能破坏周围的布局。跨屏幕大小也是如此:相对单位让一个样式表适应手机和显示器,这是响应式设计的基础。

你选择的单位是关于你的数字锚定到什么的决定,那个锚点就是决定布局是否对读者做出响应或忽略他们的因素。一个**绝对单位**在每个上下文中都解析为相同的计算长度。在屏幕 CSS 中,这实际上只有 px:物理单位(cmmminptpc)是相对于像素定义的(根据定义 1in96px)并属于印刷样式表。相对单位相对于可以改变的参考来解析,这就是它能适应的原因。

参考是整个游戏,所以值得命名每个相对单位指向什么。remem字体相对的:它们相对于字体大小(根的或元素的)解析。% 对大多数属性来说是父相对的:百分比宽度是包含块宽度的一部分。vwvh视口相对的:浏览器视口(页面的可见区域)的一部分。实际规则由此而来:用相对单位调整类型和布局,对不应该缩放的东西保留 px一个设置更大默认字体大小或缩放页面的读者会移动相对单位指向的参考,所以页面会增长以满足他们;一个 px 值没有参考来移动,保持不变,这是你试图避免的可访问性失败。

Juno绝对单位 vs 相对单位px 这样的绝对单位是永远不变的固定大小。相对单位缩放到其他东西,比如读者的字体大小或屏幕宽度。相对单位让页面适应看它的人,这就是为什么它们对设置更大文本大小的读者很重要。
Juno绝对单位 vs 相对单位px 是你实际会使用的唯一绝对单位;其他一切都缩放到一个参考。remem 缩放到字体,% 到父元素,vwvh 到视口。选择相对单位,这样当读者提高默认字体大小时页面会增长,而不是忽略他们。
Juno绝对单位 vs 相对单位 每个单位都是一个数字加一个锚点,锚点决定布局是否能响应。px 没有可以移动的锚点,所以它永远不适应;remem 锚定到字体,% 到父元素,vwvh 到视口。用相对单位调整类型和布局,对应该保持固定的部分保留 px

像素以及何时它们很好用

一个**像素**(px)是一个小的固定长度单位。它是最直接推理的,因为 16px 总是 16px。这使它很适合应该保持相同大小的小东西,无论什么:边框的厚度、一个小的圆角、一个固定的图标。

css
.card {
  border: 1px solid #ccc;      /* 一条细线边框,始终是 1px */
  border-radius: 8px;          /* 一个固定的圆角 */
}

这里的问题是像素不考虑读者。如果有人将他们的浏览器设置为显示更大的文本,一个你锁定为 24px 的标题会保持 24px 并忽略他们的选择。这就是为什么 px 对边框和小细节是个不错的选择,但不是你想要用于文本的单位。

当你希望长度保持不变时,px 是要选择的单位:边框、细线分割线、小的固定半径和偶尔不应该缩放的图标。对于这些,它的固定性是重点。一个 1px 的边框如果随读者的字体大小增长会看起来不对,所以固定它是正确的。

css
.card {
  border: 1px solid #ccc;      /* 无论字体大小如何都保持细线 */
  border-radius: 8px;
  padding: 1rem;               /* 但内部间距随类型缩放 */
}

缺点是不应该用它调整文本大小的原因。读者可以在浏览器中设置更大的默认字体大小以获得舒适或可访问性,而 px 会覆盖它:一个 font-size: 18px 的标题无论他们的默认是 16 还是 24 都会以 18 像素渲染。所以用 px 处理固定细节,并切换到字体相对单位处理任何应该尊重读者设置的东西,下一节涵盖这一点。

CSS px 不是物理设备像素;它是一个参考像素,一个角度单位,浏览器缩放使得 1px 在屏幕密度间读起来大小一致。在高密度显示器上,一个 CSS 像素映射到多个设备像素,这就是为什么一个 1px 的边框保持一条清晰的细线而不是消失。那种固定性使 px 对不应该跟踪读者字体大小的东西是正确的调用:边框、1px 分割线、小半径、box-shadow 偏移和细线细节。

css
.card {
  border: 1px solid #ccc;      /* 固定的细线;缩放它看起来会很奇怪 */
  border-radius: 8px;
  padding: 1rem;               /* 内部间距改为跟踪类型 */
}

失败模式是用 px 调整文本大小。设置 font-size 为像素会覆盖读者的默认字体大小,这是他们可以在浏览器偏好中设置的基本大小(通常是为了低视力),因为一个 px 值没有参考来针对那个偏好缩放。注意与页面缩放的区别:现代浏览器确实在全页缩放时缩放 px,所以旧的"px 忽略缩放"声明已经过时,但是一个 px 字体大小仍然忽略默认字体大小设置具体来说,那个设置是许多读者依赖的可访问性路径。保持的规则:px 用于固定细节,用字体相对单位处理任何读者应该能够放大的东西,特别是正文和排版

Juno像素以及何时它们很好用 像素(px)是固定大小,所以 16px 总是 16px。这使它很适合应该保持不变的小东西,如 1px 边框或一个小圆角。权衡是 px 忽略设置了更大文本的读者,所以它不是你想要用于页面上单词的单位。
Juno像素以及何时它们很好用 当长度不应该缩放时使用 px:边框、细线分割线、小半径。它的固定性是那里的特点。缺点显示在文本中,其中一个 px 字体大小覆盖读者更大的默认,所以对固定细节保留 px 并用字体相对单位调整文本大小。
Juno像素以及何时它们很好用 CSS px 是一个参考像素,浏览器在屏幕密度间保持其视觉一致,这就是为什么一个 1px 边框保持干净的细线。这使它对边框和阴影这样的固定细节是正确的。它对文本是错的,因为一个 px 字体大小忽略读者的默认字体大小设置,所以改为用 rem 调整类型。

em 和 rem

两个相对单位缩放到字体大小:emrem。要选择的是**rem**。它相对于页面的根字体大小进行测量,这是设置在整个文档上的基本文本大小(默认为 16px)。所以 1rem16px1.5rem24px2rem32px

css
h1 {
  font-size: 2rem;             /* 2 x 16px = 32px */
}
p {
  font-size: 1rem;             /* 16px,基本大小 */
  margin-bottom: 1.5rem;       /* 下方 24px 的空间 */
}

因为 rem 与那一个根大小相关联,它是可预测的:1.5rem 在页面的任何地方都意味着同样的事情。当读者提高他们的默认文本大小时,所有用 rem 调整大小的东西一起增长。另一个单位 em 改为缩放到元素自己的字体大小,这可能会变得混乱,所以从 rem 开始,你很少会陷入困境。

emrem 都是字体相对的,差异是它们相对于哪个字体大小来测量。rem 相对于字体大小,设置在 <html> 元素上的大小(默认为 16px),所以 1.5rem 在页面的任何地方解析为相同的长度。em 相对于元素自己的字体大小,所以它的值根据你使用它的位置而变化。

css
h1 {
  font-size: 2rem;             /* 始终是根的 2 倍 = 32px */
}
.card {
  font-size: 1.125rem;         /* 18px */
  padding: 1em;                /* 1 x 这个元素的 18px = 18px */
}

建议是rem 调整大小,仅对与本地字体大小绑定的缩放使用 emem 对应该跟踪他们自己文本的东西很有效,比如按钮内的内边距,随着按钮的字体大小增长。但 em 通过嵌套元素复合,这会让人惊讶,所以将其保留用于这些本地情况,让 rem 承载你的通用尺寸和排版

emrem 都是字体相对的,意思是它们相对于字体大小而不是固定长度来解析,区别在于参考。rem(root em)相对于根字体大小来解析,在 <html> 元素上计算的 font-size,所以它是一个单一的全局参考:1.25rem 在标题、页脚或六层深处是相同的计算长度。em 相对于当前元素的 font-size 来解析,所以它的意义是本地的并随上下文移动。

那个本地参考是 em 复合的地方。因为子元素的 em 相对于其自己的 font-size 来测量,而 font-size 本身继承,在嵌套元素上设置 font-sizeem 会在每个级别乘以:

css
/* 每个列表级别都用 em 设置 font-size,所以大小以乘法方式堆叠 */
ul { font-size: 0.9em; }       /* 0.9 x 父级 */

/* 一个 16px 的根变成:
   深度 1 -> 14.4px
   深度 2 -> 12.96px  (0.9 x 0.9)
   深度 3 -> 11.66px  (0.9 x 0.9 x 0.9)  */

没人要求文本随嵌套深度而缩小;那是 em 复合,这是默认选择 rem 的主要论证。权衡从另一个方向运行,用于组件本地缩放,其中你想要一个值跟踪一个元素自己的类型:一个内边距为 0.75em 和边框半径 0.5em 的按钮当你提高其 font-size 时作为一个单元重新缩放,rem 不能做这个因为它忽略本地大小。所以实际的分割是 rem 用于应该对根保持稳定的任何东西,em 用于应该随他们自己元素字体大小缩放的间距和半径。

对于流体尺寸,min()max()clamp() 让长度在边界之间灵活。min(a, b) 在当前视口处选择较小的,max(a, b) 选择较大的,clamp(min, preferred, max) 在最小值和最大值之间保持首选值。一个常见的标题模式是 font-size: clamp(1.75rem, 4vw, 3rem):它随视口缩放(4vw)但永远不会降到 1.75rem 以下或超过 3rem,所以类型保持流体而不需要一堆断点。用 rem 调整类型大小(或 rem 界定的 clamp())也尊重用户缩放和读者的默认字体大小,因为那些调整 rem 解析到的根,而一个原始 vw 值只跟踪视口并忽略读者的字体偏好。这就是为什么 clamp() 中的 rem 最小值和最大值很重要:它们在表达式中保留可访问的参考。

Junoem 和 remremem 都缩放到字体大小,要开始的是 rem。它相对于页面的根大小进行测量,默认为 16px,所以 1.5rem24px 并在任何地方意味着相同的事情。em 改为缩放到元素自己的字体大小,这可能会变得混乱,所以首先选择 rem
Junoem 和 rem 两者都是字体相对的:rem 相对于根字体大小测量,所以它在任何地方都是稳定的,而 em 相对于元素自己的字体大小测量,所以它随上下文移动并在嵌套时复合。默认用 rem 调整大小,为应该跟踪其自己元素类型的间距保留 em,比如按钮内的内边距。
Junoem 和 remrem 锚定到根字体大小以获得一个稳定的参考;em 锚定到元素自己的大小并通过嵌套乘以,这就是为什么深度嵌套的 em 字体大小会漂移。对通用尺寸使用 rem 和应该跟踪其自己类型的组件本地缩放使用 em。对于流体类型,clamp(1.75rem, 4vw, 3rem) 随视口灵活变动,同时 rem 最小值和最大值保持它尊重用户缩放和字体设置。

百分比

一个**百分比**(%)相对于其父元素调整元素大小。对于宽度,width: 50% 意味着元素所在盒子宽度的一半,无论那个宽度恰好是多少。

css
.sidebar {
  width: 25%;                  /* 父级宽度的四分之一 */
}
.content {
  width: 75%;                  /* 剩余四分之三 */
}

这就是使布局流体的原因:因为宽度是父级的分数,他们随着父级缩小和增长。调整窗口大小,一个 50% 的列会保持宽度的一半,而不是像固定 500px 列那样溢出边缘。那种灵活性就是百分比在响应式设计中经常出现的原因。

一个**百分比**相对于父级上的参考解析,对于 width 那个参考就是父级的内容宽度。所以 width: 50% 给你包含盒子当前宽度的一半,这就是使百分比列流体的原因:他们跟踪父级的尺寸变化。

css
.container {
  width: 90%;                  /* 其父级的 90%,最高达到下面的上限 */
  max-width: 60rem;            /* 在宽屏上停止在 60rem 之后增长 */
  margin: 0 auto;              /* 居中 */
}

参考并不总是宽度,这会让人困惑。一个百分比 paddingmargin,即使是竖直的,也相对于父级的宽度解析,而不是其高度。一个百分比 height 相对于父级的高度解析,但只有在父级有明确的高度来测量,否则它没有什么可解析的并被忽略。将百分比宽度与 rem 中的 max-width 配对,如上所示,是常见的做法:流体至一个点,然后被限制以便行不会太宽而难以阅读。

一个**百分比**是相对的,但与 remem 不同,它的参考不是字体大小,而是包含块的一个维度(为定位或内流元素建立参考的盒子,通常是父级的内容盒子)。陷阱在于参考维度是属性特定的,并不总是你期望的:

css
.hero {
  width: 80%;                  /* 包含块宽度的 80% */
  padding-top: 25%;            /* 也是宽度的 25%,不是高度 */
  margin-bottom: 10%;          /* 再次是宽度,尽管它是竖直的 */
}

widthpaddingmargin 百分比都相对于包含块的宽度解析,包括竖直的内边距和边距。那种基于宽度的竖直内边距不是绕开的怪癖;它是在 aspect-ratio 出现之前用于固定宽高比盒子的经典技巧,因为 padding-top: 56.25% 给出一个 16:9 区域,随宽度缩放。一个 height 百分比相对于包含块的高度解析,但只有在那个高度是明确的(明确设置或其他方式可解析);对于自动高度它计算为 auto 并显示什么都不做,这通常是百分比高度无声失败的原因。在现代布局中,flex-basis 和网格轨道百分比表现得更可预测,所以百分比对流体宽度保持有用,同时 fr 单位和 min()/max()/clamp() 覆盖百分比处理起来尴尬的情况。

Juno百分比 百分比相对于父级调整大小,所以 width: 50% 是元素所在盒子宽度的一半。这使列流体:调整窗口大小,它们增长和缩小而不是溢出。它是支撑适应任何屏幕的布局的主要工具之一。
Juno百分比 百分比宽度是父级的分数,这就是当容器调整大小时保持列流体的原因。注意参考:百分比内边距和边距相对于父级的宽度解析,即使是竖直的,而百分比高度需要父级有明确的高度。将百分比宽度与 rem 中的 max-width 配对保持它流体但受限。
Juno百分比 百分比相对于包含块解析,参考是属性特定的:widthpaddingmargin 都使用其宽度,竖直值包括在内,这是宽度基础宽高比盒子背后的技巧。百分比高度需要明确的父级高度或它计算为 auto 并什么都不做。保留百分比用于流体宽度,让 fr 单位和 clamp() 处理尴尬的情况。

视口单位

视口单位相对于浏览器窗口本身调整大小。vw 是视口宽度的百分比,vh 是视口高度的百分比,其中视口是页面的可见区域。所以 100vw 是窗口的全部宽度,100vh 是其全部高度。

css
.hero {
  height: 100vh;               /* 填满整个屏幕高度 */
}

这是全屏部分的首选,比如应该填满窗口(无论大小如何)的登陆横幅。因为单位跟踪窗口,当有人调整或旋转他们的设备时部分保持全屏,不需要你设置一个只在一个屏幕上正确的固定像素高度。

视口单位相对于视口进行测量,浏览器窗口的可见区域。vw 是视口宽度的百分之一,vh 是其高度的百分之一,所以 100vh 是一个完整窗口的高度,50vw 是其宽度的一半。它们是全屏部分和应该填满任何大小窗口的英雄横幅的自然选择。

css
.hero {
  min-height: 100vh;           /* 至少是一个完整屏幕高 */
  padding: 2rem;
}

在移动设备上要知道一件事:100vh 历史上包括浏览器地址栏后面的空间,所以一个全高部分可能坐得比可见区域高,并在底部被切断。修复是 dvh动态视口高度,它跟踪实际可见高度,因为浏览器铬黄显示和隐藏。在移动全屏部分上选择 min-height: 100dvh,并注意原始 vw 在字体大小上忽略读者的字体设置,所以保留视口单位用于布局而不是类型。

视口单位相对于视口来解析,浏览器窗口的可见渲染区域。vwvh 是其宽度和高度的百分之一;vminvmax 是两者中较小和较大的百分之一,对应该响应方向的值很方便。它们的参考是窗口,不是任何父级,所以它们是独立于周围布局的全视口部分的正确工具。

css
.hero {
  min-height: 100dvh;          /* 完整可见高度,移动安全 */
  padding: 2rem;
}

锐角是移动设备,其中视口高度不是一个数字。浏览器的地址栏和工具栏随用户滚动展开和折叠,所以 100vh 被固定到最大可能的视口,一个全高部分会在铬黄后面溢出。CSS 现在公开三个:svh(小视口高度,铬黄展开),lvh(大,铬黄折叠),和 dvh动态,实时跟踪当前状态)。对必须适应可见区域的全屏部分使用 dvh,接受它随着栏移动而重排。另一个陷阱是原始 vw 中的 font-size:因为视口单位的参考是窗口而不是根字体大小,font-size: 4vw 忽略读者的默认字体大小和不改变视口的页面缩放,这与 px 字体大小测试相同的可访问性失败。修复是将其限制:clamp(1rem, 4vw + 0.5rem, 2rem) 保持流体行为,同时 rem 条款恢复读者的设置可以移动的参考。

Juno视口单位vwvh 相对于浏览器窗口调整大小:100vw 是其全部宽度,100vh 是其全部高度。它们是全屏部分(比如登陆横幅)的首选,因为当窗口调整大小时它保持全屏,而不是被锁定到一个像素高度。
Juno视口单位vwvh 是窗口宽度和高度的百分之一,这使它们对应该在任何大小屏幕填满的英雄部分是正确的。在移动设备上,100vh 可以在地址栏后面运行得更高,所以在那里选择 dvh。保留视口单位用于布局,而不是字体大小,因为原始 vw 在类型上忽略读者的设置。
Juno视口单位 视口单位锚定到窗口,不是父级,所以它们适合全视口部分;vminvmax 响应方向。在移动设备上高度不是一个值,所以使用 dvh 跟踪可见区域,因为浏览器铬黄移动。永远不要用原始 vw 调整类型大小,因为它忽略读者的字体设置;在一个 clamp() 中用 rem 条款限制它,所以一个可访问的参考保留在表达式中。