这篇文章解释了正常的流程,或者如果你没有改变网页元素的布局,它们的布局方式。
正如在上一节介绍布局的课程中详细介绍的那样,如果你没有应用任何CSS来改变它们的行为方式,网页上的元素就会以常规流布局。而且,正如我们开始发现的那样,你可以通过调整它们在常规流中的位置或将它们从正常流动中完全移除来改变元素的行为。从一个坚实的、结构良好的文档开始,在正常的流程中是可读的,这是开始任何网页的最好方式。它确保您的内容是可读的,即使用户使用一个非常有限的浏览器或设备,如屏幕阅读器读取页面的内容。此外,由于常规流的设计目的是制作可读的文档,因此以这种方式开始,您将与文档一起工作,而不是在更改布局时与之抗争。
在深入研究不同的布局方法之前,有必要回顾一下您在前面的模块中关于常规流的一些内容。
这个过程开始于单个元素的盒子以这样一种方式布局,即它们碰巧拥有的任何填充、边框或边距都被添加到它们的内容(content
)中。这就是我们所说的盒子模型(box model
)。
默认情况下,块级元素的内容填充包含它的父元素的可用行内空间,并沿块尺寸增长以容纳其内容。内联级元素的大小就是其内容的大小。你可以在一些默认display属性值为inline
的元素上设置width或height,比如,但是
display
值仍然是inline
的。
如果你想以这种方式控制内联级元素的display
属性,使用CSS将其设置为块级元素(例如,使用display: block;
或者display: inline-block;
,它混合了两者的特征)。
这解释了元素是如何单独构建的,但是当它们彼此交互时,它们是如何构建的呢?常规流(在布局介绍文章中提到)是将元素放置在浏览器视口中的系统。默认情况下,块级元素
按照块流方向(block flow direction
)布局,该方向基于父元素的写入模式(初始值:horizontal-tb
)。每个元素将出现在上一个元素下面的新行上,每个元素之间用指定的任何边距(margin
)分隔。例如,在英语中,(或任何其他水平的,从上到下的书写模式)块级元素是垂直布局的。
内联元素
的行为不同。它们不会出现在新行上;相反,只要在父块级元素的宽度范围内有足够的空间,它们都与相邻的(或换行的)文本内容放在同一行。如果没有空间,那么溢出的内容将移到新的一行。
如果两个垂直相邻的元素都设置了边距,并且它们的边距相互接触,则两个边距中较大的保留,较小的消失。这就是所谓的边缘塌陷(margin collapsing
)。折叠边距仅在垂直方向(vertical direction
)上相关。
Flexbox是一种用于按行或列排列项目的一维布局方法。项可伸缩(扩展,flex (expand)
)以填充额外的空间或收缩以适应更小的空间。本文解释了所有的基本原理。
很长一段时间以来,唯一可靠的跨浏览器兼容的工具,用于创建CSS布局是像浮动(floats
)和定位(positioning
)功能。这些方法是有效的,但在某些方面,它们也有限制和令人沮丧。
以下简单的布局设计是很难或不可能用这种工具以任何方便、灵活的方式实现的:
正如您将在后面的小节中看到的,flexbox使许多布局任务变得更加容易。让我们开始吧!
在本文中,您将通过一系列练习来帮助您理解flexx是如何工作的。要开始,你应该从GitHub的repo中复制第一个启动文件flexbox .html。在现代浏览器(如Firefox或Chrome)中加载它,并在代码编辑器中查看代码。你也可以在这里看到现场直播。
您将看到,我们有一个
元素,其中包含一个顶级标题,以及一个元素,其中包含三个
。我们将使用这些来创建一个相当标准的三列布局。
首先,我们需要选择将哪些元素布置为弹性盒子。为此,我们在想要影响的元素的父元素上设置一个特殊的display
值。在本例中,我们想要布局元素,所以我们在
上设置:
section {
display: flex;
}
这会导致
元素变成一个flex 容器(flex container
),它的子元素变成flex 项(flex items)。这样做的结果应该像这样:
因此,这个声明就提供了我们所需要的一切。难以置信的,对吧?我们有多列布局,列的大小相同,列的高度相同。这是因为为flex项(flex容器的子项)设置的默认值是为了解决诸如此类的常见问题。
为了清楚起见,让我们重申一下这里发生了什么。我们给display
设置flex
值的元素在与页面其他部分交互方面表现得像一个块级元素,但它的子元素被布置为flex
项。下一节将更详细地解释这意味着什么。还需要注意的是,如果您希望将元素的子元素作为flex项进行布局,但又希望该元素表现得像内联元素一样,则可以使用display
的inline-flex
值。
当元素作为flex 项(flex items
)布局时,它们沿着两个轴进行布局:
main axis
)是沿着 flex 项的布局方向运行的轴(例如,作为页面上的一行,或页面上的一列)。这个轴的起点和终点称为主起点(main start)和主终点(main end)。cross axis
)是垂直于flex 项布局方向的轴。这个轴的起点和终点称为交叉起点(cross start
)和交叉终点(cross end
)。display: flex
的父元素(在我们的例子中是
)称为flex容器(flex container
)。
元素)。在阅读后续章节时,请记住这个术语。如果你对所使用的任何术语感到困惑,你可以随时查阅它。
Flexbox提供了一个名为flex-direction的属性,用于指定主轴运行的方向(Flexbox子节点的布局方向)。默认情况下,它被设置为row
,这将使它们按照浏览器默认语言的工作方向(从左到右,对于英语浏览器)排成一行。
尝试在规则中添加以下声明:
flex-direction: column;
您将看到,这将条目放回到列布局中,就像我们添加任何CSS之前一样。在继续之前,请从示例中删除此声明。
注意:您还可以使用
row-reverse
和column-reverse
值以相反的方向布局伸缩项。也试试这些值吧!
当你在布局中有一个固定的宽度或高度时,出现的一个问题是,最终你的flexx子节点会溢出它们的容器,破坏布局。看看我们的flexbox-wrap0.html示例,并尝试实时查看它(如果你想跟随这个示例,现在就获取该文件的本地副本):
在这里,我们看到子元素确实是从他们的容器中挣脱出来的。解决这个问题的一种方法是在规则中添加以下声明:
flex-wrap: wrap;
同时,在规则中添加以下声明:
flex: 200px;
现在试试这个。你会发现,包含以下内容后,布局看起来好多了:
现在有多行了。每一行都有合理地尽可能多的flexbox填满它。任何溢出都向下移动到下一行。在文章上设置flex: 200px
声明意味着每篇文章的宽度至少为200px。我们将在后面更详细地讨论这个属性。您可能还注意到,最后一行的最后几个子元素都变宽了,因此整个行仍然是填满的。
但我们能做的还有很多。首先,尝试将flex-direction属性值更改为行反向(row-reverse
)。现在您将看到您仍然拥有多行布局,但是它从浏览器窗口的另一个角落开始,并反向流动。
在这一点上,值得注意的是flex-direction
和flex-wrap
有一个简写:flex-flow
。例如,你可以替换
flex-direction: row;
flex-wrap: wrap;
为
flex-flow: row wrap;
现在让我们回到我们的第一个例子,看看我们如何控制与其他flex 项相比,flex 项占用的空间比例。启动flexbox1.html的本地副本,或者将flexbox1.html的副本作为新的起点(see it live)。
首先,在CSS的底部添加以下规则:
article {
flex: 1;
}
这是一个无单位的比例值,用于指示每个flex项相对于其他flex项在主轴上占用多少可用空间。在本例中,我们为每个元素赋予相同的值(值为1),这意味着在设置了
padding
和margin
等属性后,它们都将占用等量的剩余空间。这个值在flex项之间按比例共享:将每个flex项的值设置为400000将具有完全相同的效果。
现在在前面的规则下面添加以下规则:
article:nth-of-type(3) {
flex: 2;
}
现在,当您刷新时,您将看到第三个占用的可用宽度是其他两个的两倍。现在总共有四个可用的比例单位(因为1 + 1 + 2 = 4)。前两个伸缩物品各有一个单位,所以它们各占可用空间的
1/4
。第三个有两个单元,所以它占用了可用空间的2/4
(或1 / 2
)。
您还可以在flex值中指定最小大小值。尝试像这样更新你现有的文章规则:
article {
flex: 1 200px;
}
article:nth-of-type(3) {
flex: 2 200px;
}
这基本上说明,“每个flex项首先会被赋予200px的可用空间。在此之后,剩余的可用空间将按照比例单位共享。”尝试刷新,您将看到空间共享方式的不同。
flexbox的真正价值体现在它的灵活性/响应性上。如果您调整浏览器窗口的大小或添加另一个元素,布局将继续正常工作。
Flex是一个简写属性,最多可以指定三个不同的值:
我们建议不要使用全写flex 属性,除非你真的需要(例如,覆盖之前设置的东西)。它们会导致编写大量额外的代码,并且会让人有些困惑。
您还可以使用flexbox 特性沿主轴或交叉轴对齐flex项。让我们通过查看一个新示例来探讨这个问题:flex-align0.html(也请参见在线示例)。我们将把它变成一个整洁、灵活的按钮/工具栏。现在你会看到一个水平菜单栏,一些按钮挤在左上角。
现在,将以下内容添加到示例的CSS底部:
div {
display: flex;
align-items: center;
justify-content: space-around;
}
刷新页面,您将看到按钮现在很好地位于水平和垂直的中心。我们通过两个新的性质来实现。
align-items控制flex项在交叉轴上的位置:
stretch
,它将拉伸所有flex项以沿交叉轴的方向填充父项。如果父项在交叉轴方向上没有固定的高度,那么所有的flex项都将与最高的flex项一样高。这就是我们的第一个示例在默认情况下具有相等高度的列的方式。center
值使项目保持其固有尺寸,但沿着交叉轴居中。这就是为什么我们当前示例的按钮垂直居中。flex-start
和flex-end
这样的值,它们将分别在交叉轴的开始和结束处对齐所有项。有关详细信息,请参阅align-items。您可以通过对单个flex项应用align-self属性来覆盖它们的align-items行为。例如,尝试在CSS中添加以下内容:
button:first-child {
align-self: flex-end;
}
justify-content控制flex项在主轴上的位置。
flex-start
,它使所有项位于主轴的起点。flex-end
来使它们坐在末端。center
也是justify-content
的值。它将使伸缩项目位于主轴的中心。space-around
很有用——它将所有的项目均匀地分布在主轴上,在两端都留下一点空间。space-between
,它与space-around
非常相似,只是它在两端都不留下任何空间。在弹性布局中,justify-items属性被忽略。
我们鼓励你在继续之前尝试一下这些值,看看它们是如何工作的。
Flexbox还有一个特性,可以在不影响源顺序的情况下更改flex项的布局顺序。这是另一件传统布局方法无法做到的事情。
这方面的代码很简单。尝试将以下CSS添加到按钮栏示例代码中:
button:first-child {
order: 1;
}
刷新后,你会看到“Smile”按钮已经移动到主轴的末端。让我们更详细地讨论一下这是如何工作的:
order
值为0
。order
值的Flex项将比具有较低指定order
值的项在显示顺序中显示较晚。order
值的Flex项将按source order显示。因此,如果您有四个项,其顺序值分别设置为2、1、1和0,那么它们的显示顺序将是第4、第2、第3和第1。order
值,并且在source order中位于第二项之后。可以设置负序值,使项比值为0的项显示得早。例如,你可以使用以下规则使“腮红”按钮出现在主轴的开始:
button:last-child {
order: -1;
}
使用flexbox可以创建一些非常复杂的布局。将flex项设置为flex容器是完全可以的,这样它的子项也可以像弹性盒子一样布局
。请查看complex-flexbox.html(也请查看现场)。
让我们看一下用于布局的代码。 首先,我们将 接下来,我们在 接下来,我们选择第一个 最后,我们在按钮上设置一些大小。这次给它一个flex值 大多数新浏览器都支持Flexbox: Firefox、Chrome、Opera、Microsoft Edge和IE 11,以及更新版本的Android/iOS等。然而,你应该意识到仍然有旧的浏览器不支持Flexbox(或者支持,但支持一个非常旧的,过时的版本)。 当你只是在学习和实验时,这并不重要;然而,如果你考虑在一个真实的网站中使用flexbox,你需要做测试,并确保你的用户体验在尽可能多的浏览器中仍然是可接受的。 Flexbox比一些CSS特性要棘手一些。例如,如果浏览器缺少CSS下拉阴影,那么站点可能仍然可用。然而,不支持flexbox功能可能会完全破坏布局,使其无法使用。 我们将在跨浏览器测试模块中讨论克服跨浏览器支持问题的策略。 你已经看完了这篇文章,但是你还记得最重要的信息吗?在继续学习之前,您可以找到一些进一步的测试来验证您是否记住了这些信息——参见测试您的技能:Flexbox。 CSS网格布局是一个面向web的二维布局系统。它允许您以行和列的形式布局内容。它有许多功能,使构建复杂的布局直截了当。这篇文章将解释所有你需要知道的开始使用网格布局。 网格是水平线和垂直线的集合,我们可以根据它来排列我们的设计元素。它们帮助我们创建布局,使我们的元素在页面之间移动时不会跳跃或改变宽度,从而在我们的网站上提供更大的一致性。 网格通常有列( 确定了设计所需的网格后,可以使用CSS网格布局来创建它。我们将首先查看网格布局的基本功能,然后探索如何为您的项目创建一个简单的网格系统。 作为起点,在文本编辑器和浏览器中下载并打开起点文件(您也可以在这里看到它)。您将看到一个带有容器的示例,其中包含一些子项。默认情况下,这些显示在正常流中,因此这些框一个显示在另一个下面。我们将在本课的第一部分使用此文件,进行更改以查看其网格行为。 要定义网格,我们使用display属性的 与Flexbox不同的是,这些 grid 项不会立即看起来有任何不同。声明 为了看到看起来更像网格的东西,我们需要向网格添加一些列。让我们添加三个200像素的列。您可以使用任何长度单位或百分比来创建这些列。 将第二个声明添加到CSS规则中,然后重新加载页面。您应该看到项目已经重新排列,这样在网格的每个单元格中都有一个。 除了使用长度和百分比创建网格之外,我们还可以使用 将您的列表更改为以下定义,创建三个 你现在有了灵活的tracks。 第一个track 获得 注意: 为了在tracks之间创建间隙,我们使用以下属性: 这些间隙(gaps)可以是任何长度单位或百分比,但不能是 注意: 您可以使用CSS 现在您将得到三个 到目前为止,我们只指定了列轨道,但是要创建行来保存内容。这是显式( 差别是: 默认情况下,在隐式网格中创建的轨道是自动( 如果我们将内容添加到高于100像素的轨道中,那么100像素高的轨道就不太有用了,因为在这种情况下会导致溢出。 minmax()函数允许我们设置轨道的最小和最大尺寸,例如, 如果您添加额外的内容,您将看到轨道扩展以允许它适合。注意,扩展是沿着行进行的。 我们可以结合我们所学到的关于轨道列表、重复符号和minmax()的一些经验来创建一个有用的模式。有时,要求grid创建尽可能多的列以适应容器是很有帮助的。我们通过使用 这是有效的,因为grid创建了尽可能多的200像素的列,以适应容器,然后共享所有列之间的剩余空间。最大值是 现在我们继续从创建网格到在网格上放置东西。我们的网格总是有线条——这些线条从1开始编号,与文档的书写模式有关。例如,英语中的第一条列分隔线(从左到右书写)将位于网格的左侧,第一条行分隔线位于顶部,而在阿拉伯语中(从右到左书写),第一条列分隔线将位于右侧。 我们根据这些分隔线来放置元素,通过以下属性来指定从那条线开始到哪条线结束。 这些属性的值都是一个分隔线序号。你也可以使用简写属性: 它们允许您一次指定开始分隔线序号和结束分隔线序号,用正斜杠 下载这个文件作为起点,或者在线。它定义了一个的网格和一个简单的文章轮廓。您可以看到,自动放置( 让我们用网格线来为我们的站点安排所有的元素。在CSS的底部添加以下规则: 注意:您也可以使用值 在网格上安排项的另一种方法是使用grid-template-areas属性,并为设计中的各种元素命名。 从上一个示例中删除基于分隔线的定位(或重新下载文件以获得新的起点)并添加以下CSS。 你可以随意调整布局,将页脚改为仅位于文章下方,将侧边栏改为一直向下延伸。这是一种很好的描述布局的方式,因为只看CSS就能清楚地知道到底发生了什么。 网格“框架”倾向于基于12列或16列网格。有了CSS Grid,你不需要任何第三方工具来给你这样一个框架——它已经在规范中了。 下载起始点文件。这有一个定义了12列网格的容器和我们在前两个示例中使用的相同标记。现在,我们可以使用基于行的布局将内容放置在12列的网格上。 你已经看完了这篇文章,但是你还记得最重要的信息吗?在继续学习之前,您可以找到一些进一步的测试来验证您是否记住了这些信息——参见测试您的技能:网格。
此操作的HTML相当简单。我们有一个包含三个的
元素。第三个
包含三个
:
section - article
article
article - div - button
div button
div button
button
button
的子元素设置为弹性盒子。
section {
display: flex;
}
本身上设置一些
flex
值。特别注意这里的第二条规则:我们将第三个设置为让它的子元素也像flex项一样布局,但是这次我们将它们像列一样布局。
article {
flex: 1 200px;
}
article:nth-of-type(3) {
flex: 3 200px;
display: flex;
flex-flow: column;
}
flex: 1 100px;
为了有效地给它一个100px的最小高度,然后我们设置它的子元素(元素)也像flex项一样布局。在这里,我们将它们放在一个换行行中,并在可用空间的中心对齐,就像我们在前面看到的单个按钮示例中所做的那样。
article:nth-of-type(3) div:first-child {
flex: 1 100px;
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: space-around;
}
1 auto
。这有一个非常有趣的效果,如果您尝试调整浏览器窗口宽度,就会看到这个效果。这些按钮会尽可能多地占用空间。尽可能多的人可以舒服地放在一条线上;除此之外,他们将下降到一个新的线。button {
flex: 1 auto;
margin: 5px;
font-size: 18px;
line-height: 1.5;
}
4.13 浏览器兼容性
4.14 测试
5、网格(Grids)
5.1 什么是网格布局?
columns
)、行(rows
),然后每行和每列之间有空隙。这些缝隙通常被称为沟槽(gutters
)。
5.2 在CSS中创建网格
5.2.1 定义网格
<h1>Simple grid exampleh1>
<div class="container">
<div>Onediv>
<div>Twodiv>
<div>Threediv>
<div>Fourdiv>
<div>Fivediv>
<div>Sixdiv>
<div>Sevendiv>
div>
grid
值。与Flexbox一样,这支持网格布局;容器的所有直接子元素都成为网格项(grid items
)。把这个添加到你的文件中的CSS中:.container {
display: grid;
}
display: grid
将为您提供一个单列网格,因此您的项将继续像在正常流程中那样一个接一个地显示。.container {
display: grid;
grid-template-columns: 200px 200px 200px;
}
5.2.2 使用 fr 单位的灵活网格
fr
。fr
单位表示网格容器(grid container
)中可用空间的一部分,以灵活地调整网格行和列的大小。1fr
列:.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
fr
单位按比例分配空间。您可以为您的tracks指定不同的正值,如下所示:.container {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
}
2fr
的可用空间,另外两个track 获得1fr
,使第一个track 更大。您可以混合使用固定长度的单位。在这种情况下,固定轨道所需的空间首先被用完,然后剩余的空间才分配给其他轨道。
fr
单元分配的是可用空间,而不是全部空间。因此,如果你的一个轨道里面有很大的东西,就会有更少的可用空间来共享。5.2.3 网格间隙
.container {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: 20px;
}
fr
单位。
gap
属性(列间距column-gap
,行间距row-gap
和间隙gap
)以前使用grid-
前缀。规范已经更改,但带前缀的版本将作为别名进行维护。为了安全起见,让你的代码更加防弹,你可以添加这两个属性:.container {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
grid-gap: 20px;
gap: 20px;
}
5.2.4 重复track 列表
repeat()
函数重复track列表的全部或部分。更改您的track列表如下:.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
1fr
tracks ,就像以前一样。传递给repeat()
函数的第一个值指定您希望列表重复的次数,而第二个值是一个tracks列表,它可以是您希望重复的一个或多个tracks。5.2.5 显式网格与隐式网格
explicit
)网格和隐式(implicit
)网格的一个例子。
grid-template-columns
或grid-template-rows
创建。auto
)调整大小的,这通常意味着它们足够大以容纳其内容。如果希望为隐式网格轨道指定大小,可以使用grid-auto-rows和grid-auto-columns属性。如果您在CSS中添加值为100px的grid-auto-rows
,您将看到这些创建的行现在是100像素高。.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
gap: 20px;
}
5.2.6 minmax()函数
最好拥有至少100像素高的轨道,并且在添加更多内容时仍然可以扩展
。关于网页,一个相当基本的事实是,你永远不会真正知道一些东西会有多高——额外的内容或更大的字体尺寸可能会给试图在每个维度上都达到像素完美的设计带来问题。minmax(100px, auto)
。最小尺寸为100像素,但最大尺寸为auto,它将扩展以容纳更多内容。尝试更改网格自动行以使用最小最大值:.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(100px, auto);
gap: 20px;
}
5.2.7 尽可能多的列
repeat()
函数设置grid-template-columns
的值来实现这一点,但不是传递一个数字,而是传递关键字auto-fit
。对于函数的第二个参数,我们使用minmax()
,其最小值等于我们想要的最小轨道大小,最大值为1fr
。.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-auto-rows: minmax(100px, auto);
gap: 20px;
}
1fr
,我们已经知道,它在轨道之间均匀地分配空间。5.3 基于线的元素放置
/
分隔。auto-placement
)是将每个项目放置到网格上自己的单元格中。header {
grid-column: 1 / 3;
grid-row: 1;
}
article {
grid-column: 2;
grid-row: 2;
}
aside {
grid-column: 1;
grid-row: 2;
}
footer {
grid-column: 1 / 3;
grid-row: 3;
}
-1
来定位结束分隔线或行分隔线,然后使用负值从末尾开始向内计数。还要注意,线条总是从显式网格的边缘计算,而不是从隐式网格的边缘计算。5.4 使用grid-template-areas定位
.container {
display: grid;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
grid-template-columns: 1fr 3fr;
gap: 20px;
}
header {
grid-area: header;
}
article {
grid-area: content;
}
aside {
grid-area: sidebar;
}
footer {
grid-area: footer;
}
grid-template-areas
的规则如下:
.
(period)。L
形的区域。5.5 CSS网格中的网格框架
header {
grid-column: 1 / 13;
grid-row: 1;
}
article {
grid-column: 4 / 13;
grid-row: 2;
}
aside {
grid-column: 1 / 4;
grid-row: 2;
}
footer {
grid-column: 1 / 13;
grid-row: 3;
}
5.6 测试