那个盒子有多大? 了解 CSS 布局中的大小

已发表: 2022-03-10
快速总结 ↬当开始使用 Flexbox 和 Grid 时,会发现我们有时没有得到我们期望的布局可能会令人沮丧。 这通常是由于在这些新布局方法中计算尺寸的方式。 在这篇文章中,我试图准确地解释那个盒子有多大,以及它是如何变成那么大的!

Flexbox 和网格布局的一个关键特性是它们可以处理在网格和弹性项目之间、周围和内部分配可用空间。 很多时候,这只是工作,我们得到了我们希望的结果,而不需要非常努力。 这是因为规范试图默认使用最可能的用例。 但是,有时您可能想知道为什么某些东西最终会变成它的大小。 或者,您可能想做一些与默认行为不同的事情。 为此,您需要了解底层算法如何确定如何分配空间。

在本文中,我将与您分享一些关于在 CSS 中调整框大小的有趣事情。 我从规格中挑选了一些东西,我认为这些东西对于准确理解那个盒子有多大至关重要。 花点时间通读一遍,我想你会发现 Grid 中的大小调整不那么神秘了!

仔细看看 BFC

如果您曾经使用 CSS 制作过布局,那么您可能知道 BFC 是什么。 了解它为什么起作用以及如何创建它很有用,并且可以帮助您了解布局在 CSS 中的工作原理。 阅读相关文章 →

长度单位

我们可以从最熟悉的尺寸开始。 CSS 值和单位模块规范中描述的长度单位。 如果您将<length>视为 CSS 属性的允许值,则它表示此处列出的值之一。 这些值都是距离,通常由一个整数加上单位标识符组成 - 例如12px1em 。 如果值为0 ,则可以省略单元标识符。 此外,长度单位分为相对长度和绝对长度。

跳跃后更多! 继续往下看↓

相对长度

相对长度采用相对于其他事物的大小,因此如果它相对于事物发生变化,则使用相对长度定义的事物的最终大小可能会有所不同。

完整的相对单位集如下。 前四个单位是相对于字体的,而后四个是相对于视口的。

  • em
  • ex
  • ch
  • rem
  • vw
  • vh
  • vmin
  • vmax

由于这些值是相对于某物的,因此准确识别它们相对于什么是很重要的。 对于字体相对单位rem那么这总是相对于作为 HTML 文档的根元素的大小是html元素。

在下面的第一个示例中,我将html元素的字体大小设置为 20 像素。 因此1rem是 20 像素。 如果我给一个元素宽度为10rem ,它将变为 200 像素宽(因为 20px 乘以 10 是 200)。

当其他字体相对单位( emexch )用于元素的长度时,它们与应用于该元素的字体大小相关。 在第二个示例中(框的宽度为10em ), em单元查看应用于它正在调整大小的元素的字体并基于该字体进行计算。 所以,这个盒子变成了 300 像素宽,因为盒子的 font-size 是30px

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上使用 rems 和 em 进行的 Pen Sizing。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上使用 rems 和 em 进行的 Pen Sizing。

字体相对单位是根据字体大小计算的,视口相对单位是相对于称为初始包含块的矩形计算的。 在屏幕上,它具有视口的尺寸。 vw单位是视口宽度的1 / 100和高度的vh 1 / 100 。 一个宽度为50vw ,高度为50vh的盒子应该是视口宽度的一半和高度的一半。

一个盒子,它是视口高度的 50% 和宽度的 50%
vhvw单位,代表视口高度和宽度的1 / 100

vminvmax单位很有用,因为它们允许您相对于视口的较大或较小尺寸来调整某些东西的大小。 例如,这意味着您可以制作视口最长边的 50%。 当有人可能以横向或纵向模式持有设备时,这尤其有用。 vmin单元始终解析为 small 或vwvh ,而vmax解析为较大的vwvh 。 因此,如果您希望宽度始终为设备最长边的 20%,则可以使用20vmax 。 如果设备处于纵向模式,则20vmax将与20vh相同。 如果设备处于横向模式,它将与20vw相同。

下面的示例将使用vwvh大小的块与使用vminvmax大小的块进行比较。 在台式计算机或横向模式下的手机上,两个框的大小应相同。 将手机切换到纵向模式或拖动窗口以使宽度小于高度,您将看到第二个块如何更改计算的维度。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen vw 和 vh、vmin 和 vmax。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen vw 和 vh、vmin 和 vmax。
一个盒子,它是视口高度的 50% 和宽度的 50%
vmaxvmin单位:在横向格式中, vmax使用宽度,而vmin使用高度。
一个盒子,它是视口高度的 50% 和宽度的 50%
vmaxvmin单位:在纵向格式中, vmax使用高度,而vmin使用宽度。

绝对单位

绝对单位映射到物理尺寸并且不相对于屏幕上的其他事物进行缩放。 因此,当输出环境已知时,它们最有用。

下面的列表显示了 CSS 中允许的绝对单位:

  • cm
  • mm
  • Q
  • in
  • pc
  • pt
  • px

正如您所看到的,其中许多在屏幕上下文中几乎没有意义,但是,如果您正在创建用于打印的 CSS,那么当您知道您的纸张大小时,使用ptin可能会很有意义。

像素被归类为绝对长度单位,任何为 Retina 设备创建图像的人都知道,就长度而言,像素与设备像素不同。 CSS 使用了参考像素的概念,规范建议像素单位是指最接近参考像素的设备像素的整数。

参考像素是像素密度为 96dpi 且距离阅读器一臂远的设备上一个像素的视角。 对于 28 英寸的标称臂长,因此视角约为 0.0213 度。 对于在手臂长度上阅读,1px 因此对应于大约 0.26 毫米( 1 / 96英寸)。 —“CSS 值和单位模块第 3 级”,W3C

百分比

在大多数情况下,您可以使用百分比而不是长度单位来表示大小。 然后需要根据某些东西来计算这个百分比,就像解析相对长度单位一样,您正在使用的布局方法的规范将指示百分比应该是 的百分比

在规范中,您将<length-percentage>视为长度的允许值,这意味着百分比将在使用之前解析为长度。 在下面的示例中,外部元素的宽度为 400 像素,第一个子元素的宽度为 50%。 然后解析为 200 像素 - 400 的 50%。

第二个子元素的宽度使用calc ,将 50 像素添加到 50%,使该块宽 250 像素。 因此,50% 被解析为一个长度,然后用于计算。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen length-percentage。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen length-percentage。

我们这些在响应式设计时代从事网络工作的人已经习惯于使用百分比来创建看起来像是在网格上布置的布局。 以百分比工作给了我们一定程度的控制,我们需要开始放弃控制,以便充分利用 Grid 和 Flexbox 的力量!

CSS 内部和外部大小

到目前为止,我们已经了解了如何给盒子一个大小,以各种方式设置它们的宽度和高度,以及如何使用长度单位和百分比。 但是,您网页上的框是有大小的——即使您没有给它们一个大小。 了解元素在页面上的布局方式很重要,并且在使用 flexbox 和 Grid 布局时,尺寸变得越来越重要。 Grid 和 flexbox 具有很多内置的灵活性,因为它们管理的情况是显示项目所需的空间多于显示项目所需的空间,或者项目需要容纳的空间比空间无限大时它们占用的空间要少。

定义事物大小并为您提供控制该大小的其他方法的模块是 CSS Intrinsic and Extrinsic Sizing Module。 在下一节中,我们将看看这个模块定义了什么,以及为什么它对你理解 flexbox 和 grid 中的布局至关重要。

调整关键字大小

该模块的摘要说:

该模块使用代表基于内容的“内在”大小和基于上下文的“外在”大小的关键字扩展了 CSS 大小调整属性,允许 CSS 更轻松地描述适合其内容或适合特定布局上下文的框。

关键字可用于通常需要一定长度的任何属性。 例如widthheightmin-width等,此外还指定用于 Grid Layout 轨道大小和 flexbox flex-basis 。 当前3 级核心规范编辑草案中定义的关键字值是:

  • max-content
  • min-content
  • fit-content(<length-percentage>)

让我们看看如果我们将其中一些关键字用于 div 的宽度,它们会如何表现。 div 是块级元素,因此,如果你不给它一个宽度,它会延伸到内联维度中尽可能宽的宽度。 直到它到达视口或包含块的边缘。

如果一串文本比允许的空间长,它将包裹在 div 内,并且盒子会变得更高以容纳它。 要给 div 一个宽度,而不是包含块允许的空间,您可以使用前面讨论的任何长度单位。 一旦达到该长度,文本就会开始换行。

您可能希望允许内容决定大小,而不是使用长度限制框或通过它撞击包含块的边缘来限制框。 这就是这些新的基于内容的大小调整关键字的用武之地。

最小含量

在 div 上使用width: min-content ,现在 div 只会变得尽可能大,而内容在行内方向上变得尽可能小。 对于一串文本,这意味着文本会利用它所能提供的所有软包装机会。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen min-content。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen min-content。

这是此元素的最小内容大小。 它可以得到的最小的,没有任何内容以某种方式溢出。

最大内容

如果我们使用width: max-content ,则会发生相反的行为。 现在盒子变得足够大以容纳内容,如果它在内联维度上变得尽可能大的话。 我们的文本字符串现在伸展并且根本不换行。 如果它变得比这个 div 必须增长到的可用宽度更宽,这将导致溢出。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen max-content。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen max-content。
我可以使用屏幕截图来调整内容大小的关键字吗
图片来源:我可以使用内在宽度关键字吗

这些内容关键字正在传送到浏览器中,您可以在 Chrome 中使用它们,也可以在 Firefox 中作为widthheight的值使用它们。 您可以将它们用于网格布局中的轨道大小,正如我们将在下面探讨的那样,但它们在 flexbox 中还没有实现flex-basis 。 但是,现在查看这些的真正原因是要了解存在min-contentmax-content ,因为一旦我们开始研究 Flexbox 和 Grid 中的空间分布方式,具有最小和最大内容大小的事物就很重要。

CSS 网格布局中基于内容的大小

CSS 网格布局对我们刚刚探索的内容关键字进行了可靠的实现,用于调整网格轨道的大小。 这意味着您可以使内容决定网格上的轨道大小。 使用网格要记住的重要一点是它是一个二维布局模型。 如果您要求列轨道变成min-content大小,那么轨道将根据轨道中最宽的东西调整大小。

最小含量

在下一个示例中,我有一个三列跟踪网格。 使用min-content关键字调整列的大小。 其中一个单元格包含更多内容,您可以看到内容如何包装到它能够包装的地方。 以min-content大小显示此内容所需的大小成为整个轨道的大小。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的网格布局中的 Pen min-content。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的网格布局中的 Pen min-content。

最大内容

如果我们查看与min-content相同的示例,但将列更改为每个使用max-content ,您可以看到包含具有大量文本的项目的轨道如何增长以适应文本。 这导致轨道比我们定义网格的元素的大小更宽,所以它已经溢出。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的网格布局中的 Pen max-content。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的网格布局中的 Pen max-content。

适合内容

fit-content是我们尚未研究但已在 Grid Layout 中实现的关键字。 此关键字采用长度或百分比作为值。 当您使用fit-content进行轨道大小调整时,轨道将像max-content一样运行,直到达到您传入的值的大小。一旦达到该大小,轨道将停止增长,并且内容将换行。

下面示例中的所有三列轨道都使用fit-content(10em)调整大小。 如果轨道比 10em 窄,它的作用类似于max-content 。 运行时间更长的中心轨道一旦达到 10em 就会停止增长。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的网格布局中的 Pen fit-content。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的网格布局中的 Pen fit-content。

注意我创建了一个简短的视频教程来演示这些内容大小调整关键字

自动大小的轨道

在深入挖掘轨道尺寸的兔子洞之前,了解auto用于轨道尺寸的含义也很重要。 隐式网格轨道是使用auto调整大小创建的,当您开始使用 Grid 时,您通常会理解这一点。 您指定列轨道,然后将内容放入没有明确定义的行中。 行轨道会增长以包含内容,因为auto会查看内容大小并创建足够高的轨道以包含它。

但是, auto在规范中具有特定的含义。 在 Grid 和 flexbox 的情况下,如果您使用auto作为轨道大小或作为flex-basis的值,它将查看项目上是否有任何大小(或 Grid 的该轨道中的任何项目上)和将该尺寸用作基本轨道尺寸或flex-basis的值。 您可以在下面的 CodePen 中看到这种情况。 第一个示例是 Grid 布局,第二个示例是 Flex 布局。 Grid 布局有三列轨道,它们都是auto调整大小的,Flex 布局中的每个项目都可以从autoflex-basis扩展和收缩。

在这两种布局中,最终项目的宽度均为 200 像素。 您可以看到在计算轨道尺寸时如何使用该宽度。 它成为flex-basis作为最后一项,以及网格轨道的基本大小。 对于其他 Grid 轨道和弹性项目,没有宽度,因此算法使用内容大小。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid track and flex-basis of auto。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid track and flex-basis of auto。

在转向另一种调整网格轨道大小的方法之后,我们将回到auto的行为方式,以及它如何与其他轨道大小调整方法结合使用。

fr单位

本文开头讨论的所有长度单位也可用于网格布局中的轨道大小。 我们在fr单元中还有一个额外的单元。 这仅适用于网格布局,因此在网格规范中而不是在任何与尺寸相关的模块中都有详细说明。 fr单位是一个灵活的长度<flex> ,表示网格容器中剩余空间的一小部分。

fr单位不是长度,它不能像百分比或长度单位一样与calc()一起使用。

你经常会看到一个像下面这样的演示,我们使用fr单元创建了三个相同大小的轨道。 网格容器中的空间被分成了三个,并平均分配给每个轨道。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr 单元。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr 单元。

如果您的flex-basis0 ,此处的fr单元的行为与 Flexbox 的行为非常相似。 网格占用了网格容器中的所有空间,并将一个部分交给每个轨道。 但是,这样做时 Grid 不会导致轨道溢出。 如果您认为1fr的三个轨道始终是三个大小相等的轨道,则此行为可能会令人困惑。

如果我们在中间轨道中添加一个很长的单词,它不能软换行,例如Supercalifragilisticexpialidocious ,那么我们不会得到三个等宽的列。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr unit 2。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr unit 2。

Grid 仅在确保轨道足够大以容纳项目后才共享可用空间。 如果我们使用min-content ,网格会查看轨道的大小。 如果该大小小于将通过fr单元传递给轨道的大小,则不考虑内容。 如果该min-content大小大于fr单元给出的轨道,则在剩余空间被共享之前,该min-content大小用于该轨道。

因此, fr单元的行为就像使用flex-basis0的 flexbox 一样,除非该轨道的min-content大小更大,然后它的行为更像使用flex-basisauto的 flexbox。 就像我们在上一节中的auto示例一样。 如果您的等宽轨道看起来不太相等,则值得记住这一点。 可能的原因是其中一个轨道中的某些内容的min-content大小大于传递给它的内容。

使用minmax制作相等的曲目

我们现在知道为什么fr单元可能会创建比我们想要的更大的轨道。 但是,我们可以通过引入另一种特定于网格的大小调整方法 - minmax()函数来控制其行为方式。 在上面的示例中(一个轨道中的长字强制更大的min-content大小),Grid 的行为就像我们使用以下轨道大小定义一样。

 .grid { display: grid; grid-template-columns: minmax(auto,1fr) minmax(auto,1fr) minmax(auto,1fr); }

Grid 正在查看解析为content大小的auto大小,并将其用作轨道的基本大小,然后再共享任何剩余空间。

如果您希望 Grid(在上面的示例中)强制使中间轨道与网格容器中的宽度相等,即使这会导致任何溢出,您可以通过将minmax()中的第一个值设为0来实现。 正如您在下一个示例中看到的,这将导致溢出。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr unit 和 minmax。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr unit 和 minmax。

您可以看到为什么规范默认为它所做的行为。 一般来说,如果有空间显示内容,我们不希望发生溢出,但是,如果需要,您可以强制执行此操作并导致溢出。

minmax()函数在调整行大小以防止行在空时折叠到零高度时也非常有用,但仍允许它增长到允许添加任何内容的大小。 在下一个示例中,我将grid-auto-rows设置为minmax(50px, auto) 。 隐式网格中的轨道总是 50 像素高,但是您可以看到第二行更高,因为该行的一个单元格中的内容量很大。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen minmax with a max of auto。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen minmax with a max of auto。

网格布局中的百分比

虽然我们在网格布局中有fr单位、基于内容的大小和我们通常的长度单位,但您可能仍希望使用百分比来满足某些大小要求。 在大多数情况下, fr单位将是更好的选择,但是,有时您可能希望自己控制确切的百分比大小。 这样做的一个原因是,如果您在设计中排列使用 Grid 布局的元素,该设计还使用其他依赖于百分比大小的布局方法。

大多数情况下,百分比大小将按您的预期工作。 使用百分比调整大小的网格轨道将根据网格容器宽度计算百分比。 您还可以为gap属性使用百分比,这些也将根据网格容器宽度进行计算。 下面的示例具有三个列轨道,每个轨道为 30%,轨道之间的网格间隙为 5%。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的笔百分比轨迹和间隙。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的笔百分比轨迹和间隙。

需要注意的地方是在使用百分比作为垂直边距和填充时。 在 Flexbox 和 Grid 中,一个长期存在的问题意味着垂直百分比边距和填充的计算方式在浏览器之间会有所不同。

您可以在我的帖子“我们应该如何解决网格和弹性项目上的百分比边距和填充”中阅读有关此问题的更多信息,但是,我的建议和规范的建议是避免使用百分比作为边距和顶部和底部的填充时间因为结果会不一致。

网格布局中的对齐和大小调整

在网格布局中使用框对齐属性还可以更改网格中区域的大小。 考虑以下具有四个 100 像素列轨道、三个 50 像素行轨道和 20 像素间隙的布局。 网格轨道不会占据网格容器的全部区域,因此会自行对齐以在两个轴上start 。 跨越多个轨道的项目的大小是它们跨越的所有轨道和间隙的总和。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid 轨道对齐和证明。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid 轨道对齐和证明。

如果我现在使用具有space-between值的 Box Alignment 属性align-contentjustify-content ,轨道会随着间隙的增加而展开以吸收额外的空间。 现在,任何跨越多个轨道的项目都变得更大,因为它包含了现在扩大的间隙的空间。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid 跟踪 align-content 和 justify-content space-between。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid 跟踪 align-content 和 justify-content space-between。

Flexbox 和 Grid 中的空间分布比较

我认为理解诸如min-contentmax-content之类的概念在处理布局时如此重要的原因是它们使您能够开始深入挖掘布局的更精细细节。 我将用一个很好的例子来结束这篇文章,当我们需要将项目放入容器中时,我们通过比较 flexbox 和 Grid 中发生的事情来发现这一点。

该示例显示了一个包含四个弹性项目的弹性容器; 下面是一个带有四个网格项的网格容器。 此内容是相同的,但布局略有不同,尽管这些布局大致相当。 弹性项目具有autoflex-basis并且允许收缩。 网格定义定义了四个轨道,所有轨道的大小都为auto

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 flexbox 和网格中的 Pen Space 分布。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 flexbox 和网格中的 Pen Space 分布。

在 flexbox 示例中,较短的项目已折叠到其min-content大小,而较大的项目已被给予更多空间。

在 Grid 示例中,较小的项目以其max-content大小显示,因此较长的项目显示的空间较小。 当我第一次看到这种行为时,我感到很困惑。 差异的原因归结为在布局方法中计算项目大小的算法。 在 Flexbox 中,项目从max-content大小开始; 由于flex-shrink是一个正值,因此开始从每个项目中占用空间。 一旦较小的项目达到min-content大小,flexbox 就会停止占用空间以防止它们消失或溢出。

然而,网格从min-content大小的项目开始,然后添加空间。 我们的项目很快达到max-content大小,此时网格停止为它们分配空间,因为我们有一个更大的项目可以填充剩余空间。 既然您了解了min-contentmax-content ,您将能够发现曲目或项目何时以这种方式显示,这将为您提供一个深入了解并弄清楚发生了什么的起点。

大小事项!

虽然计算百分比大小以排列事物从来都不是一件有趣的事情,但至少我们都理解这一点。 它给了我们很大的控制权,尽管这意味着我们必须完成所有的工作。 开始使用 Flexbox 和 Grid 时可能会感到沮丧,只是发现有时我们没有得到我们期望的布局。 回到我们自己做这项工作并使用百分比来衡量我们的flex-basis或轨道大小可能很诱人。

然而,花一些时间调整大小,直到你对各种情况下发生的事情感到满意,最终会回报你。 您会发现您需要更少的媒体查询,并且可以依赖布局方法的固有灵活性。

为了帮助您从自己的探索开始,我尝试使本文中的示例尽可能简单,以便您可以对它们进行分叉和试验。 我在本文中分享的大部分内容都是因为我想知道如果我尝试不同的东西会发生什么,即尝试它并找出它为什么会这样工作! 因此,如果您留下的问题多于答案,请发表评论并附上演示链接,我将尝试指出规范中解释的部分。