Bootstrap 3 网格解析






4.93/5 (19投票s)
一篇关于 Bootstrap 3 网格系统功能以及实现原理的文章。
剖析 Bootstrap 响应式网格系统
内容
引言
如今的网站都追求响应式。这意味着网站会自动适应用户使用的设备。响应式是一个庞大的主题,因为它不仅涉及布局,还涉及渲染速度等...
本文将讨论 Bootstrap 3 中实现的响应式网格系统。它允许您定义网站页面在不同设备或更好地说,不同屏幕尺寸上的不同行为。文章将首先介绍此网格系统的基础,然后逐步构建更复杂的布局。在每个部分之后,我将剖析 Bootstrap 的实现,并解释所有这些成为可能的原因。
假定您具备 HTML 和 CSS 的基本知识。
那么,事不宜迟,让我们开始吧。
构建基础:我们可以做什么
网格系统:一切都围绕着行和列
网格系统的基本结构是一个容器,其中包含行,这些行被划分为 12 个相等的基数列。然后,您将布局定义为跨越一定数量的基数列。您的跨度总和必须等于 12。为此,Bootstrap 定义了一些 CSS 类,其名称结构为“col-xx-yy”。在此:
- xx:指定断点。暂时不用管它,我稍后会解释响应式断点。
- yy:一个数字,指定列的跨度。这些数字的总和必须为一行加起来等于 12。
因此,一些有效的标记是
<div class="container">
<div class="row">
<div class="col-md-4">First</div>
<div class="col-md-4">Second</div>
<div class="col-md-4">Third</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-8">The first column</div>
<div class="col-md-4">The second column</div>
</div>
</div>
如上所述:暂时不要管“col-md”,只看最后的数字。看看它们如何加起来等于 12。现在拉伸和收缩页面。在某个点,您会注意到列不再是列,而是转换为行:这就是响应式布局,也是网格系统的精髓。发生这种情况的原因是所谓的“响应式断点”,这也是“md”发挥作用的地方。
实现响应式:定义响应式断点
让我们尝试以下操作
<div class="container">
<div class="row">
<div class="col-sm-8">The first column</div>
<div class="col-sm-4">The second column</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-8">The first column</div>
<div class="col-md-4">The second column</div>
</div>
</div>
现在,再次拉伸和收缩您的浏览器窗口。您会注意到列在浏览器窗口的不同宽度下会转换为行。通过使用“sd”和“md”列类,您可以告诉网格系统在不同屏幕宽度下折叠成行。您可以使用以下断点定义器
- xs:浏览器窗口小于 768px 的断点
- sm:浏览器窗口大于或等于 768px 的断点
- md:浏览器窗口大于或等于 992px 的断点
- lg:浏览器窗口大于或等于 1200px 的断点
因此,在上面,我们使用了例如“md”,这意味着:如果您的浏览器窗口宽度大于 992px,则将屏幕分成两列,相对宽度分别为 8 和 4。如果窗口较小,则使用行。对于“sm”类,断点是 768px。当拉伸和收缩浏览器窗口时,您会注意到列确实在不同宽度下折叠。
当您在单个 div 元素上使用多个类时,有趣的就开始了
<div class="container">
<div class="row">
<div class="col-sm-2 col-lg-5">1 First</div>
<div class="col-sm-8 col-lg-2">1 Second</div>
<div class="col-sm-2 col-lg-5">1 Third</div>
</div>
<div class="row">
<div class="col-xs-4 col-md-5">2 First</div>
<div class="col-xs-4 col-md-2">2 Second</div>
<div class="col-xs-4 col-md-5">2 Third</div>
</div>
<div class="row">
<div class="col-xs-4">3 First</div>
<div class="col-xs-4">3 Second</div>
<div class="col-xs-4">3 Third</div>
</div>
</div>
我们在这里告诉 Bootstrap 在第一行使用
- 在 1200px 以上(lg 断点指定符)的宽度下,显示 3 列,相对宽度分别为 5、2、5
- 在 1200px 以下但 768px 以上(sm 断点指定符)的宽度下,显示 3 列,相对宽度分别为 2、8、2
- 768px 以下,显示所有行
还要注意,最后两行从未转换为行:我们已经指定了 xs 断点,这始终会导致列。
剖析基础:它是如何工作的?
好的,我们现在有一个由列组成的网格系统,以及响应式断点,可以根据浏览器窗口的宽度更改布局。但是所有这些东西到底是如何工作的呢?让我们找出答案。
剖析网格系统
再次查看上面的示例。您总是会看到相同的结构
- 您从一个充当容器的 div 开始
- 在这个容器中,您放入行
- 最后,您用列填充行
让我们看看它们是如何定义的。
首先是容器和行
.container {
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
}
.row {
margin-right: -15px;
margin-left: -15px;
}
如您所见,这里没什么特别的。只是设置了一些内边距和外边距。
接下来是列
.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
position: relative;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
到目前为止没有什么特别的。接下来我们将 float 属性设置为 left。
.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
float: left;
}
这很重要:float 属性通常在图像和文本环绕图像的上下文中进行解释。但它们实际上可以用于任何需要环绕的内容。让我们进一步研究一下。当对 HTML 元素应用 float 定位属性时,该元素将从元素的正常流中移除,并根据 left 或 right 的值,尽可能地放置在窗口的应用侧。
让我们尝试一下以获得感觉
<div>
<div>
Line1. Start of first long text ... and finished the first.<div style="background-color:red">First</div>Start of Second long text ... and finished the Second.<div style="background-color:green">Second</div>Start of third long text ... and finished the third.<div style="background-color:blue">Third</div>Start of fourth long text ... and finished the fourth.
</div>
</div>
<div >
<div>
Line2. Start of first long text ... and finished the first.<div style="float:left;background-color:red">First</div>Start of Second long text ... and finished the Second.<div style="float:left;background-color:green">Second</div>Start of third long text ... and finished the third.<div style="float:left;background-color:blue">Third</div>Start of fourth long text ... and finished the fourth.
</div>
</div>
<div >
<div>
Line3. Start of first long text ... and finished the first.<div style="float:right;background-color:red">First</div>Start of Second long text ... and finished the Second.<div style="float:right;background-color:green">Second</div>Start of third long text ... and finished the third.<div style="float:right;background-color:blue">Third</div>Start of fourth long text ... and finished the fourth.
</div>
</div>
请注意,我们应用了 float 的 div
- 都位于它们在未应用 float 时本应定位的行上:这就是上述句子中的“然后该元素将从元素的正常流中移除”部分。
- 根据 float 的类型,都对齐在浏览器窗口的左侧/右侧:这就是上述句子中的“尽可能地放置在窗口的应用侧”部分。
好的,但这如何应用于我们的列呢?通过对 div 应用 float 定位属性,我们可以确保它们都显示在同一行上,并且彼此相邻。如果我们不应用 float 属性,我们将得到以下结果
<div >
<div >
<div style="background-color:red">First</div>
<div style="background-color:green">Second</div>
<div style="background-color:blue">Third</div>
</div>
</div>
<div >
<div >
<div style="float:left;background-color:red">First</div>
<div style="float:left;background-color:green">Second</div>
<div style="float:left;background-color:blue">Third</div>
</div>
</div>
并通过选择左侧,第一列显示在前面,第二列显示在后面,依此类推。最后一件事可能看起来很合乎逻辑,但实际上并非如此。看下面的例子
<div >
<div >
<div style="float:right;background-color:red">First</div>
<div style="float:right;background-color:green">Second</div>
<div style="float:right;background-color:blue">Third</div>
</div>
</div>
请注意,文本“Third”如何首先显示在行上。这可能令人惊讶,但不应该。我们对带有文本“First”的 div 应用了 float,因此它被尽可能地推到右侧。然后我们对带有文本“Second”的 div 应用了 float:right,因此它被尽可能地推到右侧。但是等等:我们的第一个 div 已经在那里了。因此,第二个被尽可能地推到右侧,但位于第一个 div 的左侧。同样的思路也适用于第三个 div。
我在上面的“实际操作”示例中还有一件事要引起您的注意:请注意,带有“float:left”的 div 和带有“float:right”的 div 都大致位于同一行,尽管它们具有不同的父 div。使用 Bootstrap 网格,我们得到了漂亮的行,但在这里我们得到了一堆列。原因是 float 的工作方式:包含浮动元素的 div 不会调整其高度以适应包含这些元素的元素。这就是为什么在我们的例子中,两个父 div 的高度为零,有效地导致包含的 div 最终出现在所谓的同一行上。
让我们在这里重建一下
<div style="border:solid 1px #ff0000">
<div style="background:green;float:left">first floating left</div>
<div style="background:blue;float:left">second floating left</div>
</div>
<div style="border:solid 1px #ffff00">
<div style="background:green;float:right">first floating right</div>
<div style="background:blue;float:right">second floating right</div>
</div>
修复很简单:只需在父 div 的最后一个子元素上应用 css clear 属性
<div style="background:violet;width:50%;border:solid">
<div style="background:green;width:25%;float:left">Fourth width and floating</div>
<div style="background:yellow;width:50%;float:left">Half width and floating</div>
<div style="clear:left">the cleared div</div>
</div>
当然,尽管简单,但这并不可行。您不想为网格的每一行添加一个结束元素。这就是为什么 Bootstrap 在 CSS 中使用以下结构
.container:before,
.container:after,
.container-fluid:before,
.container-fluid:after,
.row:before,
.row:after {
display: table;
content: " ";
}
.container:after,
.container-fluid:after,
.row:after {
clear: both;
}
这可能很明显:它会在应用该类的元素之前或之后插入一个表格元素,并清除任何浮动。
关于这一点可以有很多可说的,但大部分内容 已经说过了,所以只需点击链接即可。
接下来是宽度指定符。它们定义了每列的宽度,作为 100/12 百分比的倍数,还记得我们一开始就说过 Bootstrap 网格基于 12 列吗。
.col-md-12 {
width: 100%;
}
.col-md-11 {
width: 91.66666667%;
}
...
.col-md-3 {
width: 25%;
}
.col-md-2 {
width: 16.66666667%;
}
.col-md-1 {
width: 8.33333333%;
}
好的,到目前为止我们有什么?嗯,我们有特定宽度的列,从浏览器窗口的左侧开始堆叠在一起。宽度表示为百分比,但当然问题是:百分比是多少?这就是 .container 类的定义所在。还记得我们在那里设置了外边距和内边距。因此,上面的百分比是相对于应用了 .container 和 .row 类的边距和内边距设置后剩余的宽度。
上面我展示了 md 列的指定符,但如果我们查看例如 xs 列的指定符,我们会看到相同的内容
.col-xs-12 {
width: 100%;
}
.col-xs-11 {
width: 91.66666667%;
}
...
.col-xs-3 {
width: 25%;
}
.col-xs-2 {
width: 16.66666667%;
}
.col-xs-1 {
width: 8.33333333%;
}
浏览器如何知道要应用哪个定义?这就是所谓的媒体查询的作用。
剖析响应式断点
我必须承认,我上面的说法有点误导:我遗漏了 md 情况下的定义父部分。xs 定义没有这样的父。
@media (min-width: 992px) {
.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
float: left;
}
.col-md-12 {
width: 100%;
}
.col-md-11 {
width: 91.66666667%;
}
...
.col-md-3 {
width: 25%;
}
.col-md-2 {
width: 16.66666667%;
}
.col-md-1 {
width: 8.33333333%;
}
...
}
@media 部分是所谓的媒体查询:它允许您定义应应用包含的 CSS 的条件。它是现代响应式布局的核心。因此,在上面,我们说只有当浏览器窗口至少有 992px 宽时,这些定义才应适用。您还可以查询其他属性,但对于当前的讨论,我们只需要 min-width。
container 类有类似的定义
@media (min-width: 768px) {
.container {
width: 750px;
}
}
@media (min-width: 992px) {
.container {
width: 970px;
}
}
@media (min-width: 1200px) {
.container {
width: 1170px;
}
}
这些将容器的宽度设置为从某个浏览器窗口宽度开始的固定值。但是,还有一个 css container-fluid 类,它只设置容器的外边距和内边距,因此有效地使宽度“流动”
<div class="container-fluid">
<div class="row">
<div class="col-md-3 col-xs-6">First</div>
<div class="col-md-3 col-xs-6">Second</div>
<div class="col-md-3 col-xs-6">Third</div>
<div class="col-md-3 col-xs-6">Forth</div>
</div>
</div>
但是,您可能会说,如果 xs 没有这样的父媒体查询,当您将 xs 类与其他类结合使用时,您的浏览器如何知道要选择哪个宽度?更重要的是:没有指定 max-width,因此如果您有 xs、md 和 lg 规范,当宽度大于 1200px 时,您的浏览器如何知道选择哪个?您的浏览器会使用 CSS 中的最后一个定义,而不是您在 HTML 元素上提供的列表。
让我们尝试一下,并立即出错
<html>
<head>
<title>Media Queries done Wrong</title>
<style>
@media (min-width: 300px) {
.the-small-color {
background-color:blue;
}
}
@media (min-width: 600px) {
.the-large-color {
background-color:green;
}
}
.the-default-color {
background-color:red;
}
</style>
</head>
<body>
<div class="the-default-color">
Start of first text.
</div>
<div class="the-small-color">
Start of second text.
</div>
<div class="the-default-color the-large-color">
Start of third text.
</div>
<div class="the-large-color the-default-color">
Start of fourth text.
</div>
</body>
</html>
请注意,无条件定义是最后一个。结果是第三个和第四个 div 始终是红色的,无论浏览器窗口有多宽。
另一方面,如果我们尝试以下顺序
<style>
.the-default-color {
background-color:red;
}
@media (min-width: 300px) {
.the-small-color {
background-color:blue;
}
}
@media (min-width: 600px) {
.the-large-color {
background-color:green;
}
}
</style>
现在我们得到了想要的效果:如果浏览器窗口宽度大于 600px,最后一个定义(.the-large-color)将生效,并且因为它最后定义,所以它将应用于所有包含在其类规范中的元素,无论其他定义是否存在。当浏览器窗口小于 600px 时,就好像 .the-large-color 定义不存在一样。在我们的例子中,将其与 .the-default-color 定义结合使用,div 的背景将是红色的。
这也解释了“移动优先”的说法:您应该从您希望在最小屏幕上看到的屏幕布局开始设计,然后开始添加响应式断点,以支持您想要不同布局的屏幕尺寸。
我们来看一下。我们从以下 HTML 开始
<div class="container">
<div class="row">
<div class="col-md-6">RowAColA</div>
<div class="col-md-6">RowAColB</div>
</div>
</div>
如果您在小屏幕模式下查看上面的内容,文本 RowAColA 将出现在文本 RowAColB 的上方。原因是与以下 HTML 相同,该 HTML 没有在其元素上定义任何 CSS,因此渲染相同
<div class="container">
<div class="row">
<div>RowAColA</div>
<div>RowAColB</div>
</div>
</div>
col-md-6 类中定义的属性在窗口宽度大于 992px 之前对您的浏览器是未知的。
构建复杂的网格系统
嵌套的行
虽然上面的内容看起来已经很令人印象深刻了,但这仅仅是冰山一角。Bootstrap 还允许您将行嵌套在列中。然后,要查看事物如何折叠或展开以及不同的断点,可能会变得复杂。
<div class="container-fluid">
<div class="row">
<div class="col-md-6">
<!-- nested rows inside -->
<div class="row">
<div class="col-xs-6">RowAColARow1Col1</div>
<div class="col-xs-6">RowAColARow1Col2</div>
</div>
<div class="row">
<div class="col-sm-6">RowAColARow2Col1</div>
<div class="col-sm-6">RowAColARow2Col2</div>
</div>
</div>
<div class="col-md-6">RowAColB with a very long text with lots of nonsense</div>
</div>
</div>
这里有几点需要注意
- 嵌套行中的列总共加起来是 12,而不是您可能期望的 6,因为父列的定义:还记得列的宽度是如何定义为父元素的百分比吗?在这种情况下,父列的宽度是容器宽度的一半。
- 当达到响应式断点时,RowAColB 列将出现在嵌套列下方。这是可以预期的,因为它与嵌套行所在的父行的同级。
重新排序的列
但是,最后这一点可能不是您想要的!也许您希望在折叠的情况下,最后一列出现在顶部。这就是 push 和 pull 分类器的用武之地。以及您设计屏幕的顺序:正如我之前告诉您的,在设计您的网格时,您应该考虑移动优先。这意味着网格的默认布局,即没有指定任何 CSS 类,应该是您希望在最小设备上看到的布局。然后,您开始添加 CSS 类以支持更大的屏幕。为什么这很重要?因为它决定了行的顺序以及您应该为更大的屏幕应用的重新排序类型。
这是 div 元素在 HTML 中的默认行为:占据整个宽度并按定义顺序堆叠渲染。通过应用 col-md-6 类,当屏幕宽度超过 992px 时,div 的行为就像我们定义了以下 HTML 一样
<div class="container-fluid">
<div class="row">
<div style="width:50%;float:left;">RowAColA</div>
<div style="width:50%;float:left;">RowAColB</div>
</div>
</div>
在第一个段落的解释之后,这不应该让您感到惊讶。我在这里重写它是因为我想提请您注意以下事实:
- div 的默认渲染是堆叠的,并占据整个宽度
- 通过应用 col 类之一,您可以定义 div 的宽度以及将它们并排放置的顺序
现在,回到手头的问题:如果我们希望在最小屏幕上具有特定的堆叠顺序,那么我们必须定义 div 的顺序以适应这种堆叠。如果大于屏幕的水平堆叠顺序与此顺序不同,您必须为这些屏幕使用 pull 和 push 类。通过使用 pull,您可以使定义的靠后的列首先出现。Push 是相反的:靠前的列可以出现在靠后的列之后。一个例子胜过千言万语,所以
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-push-6">RowAColA_push</div>
<div class="col-md-6 col-md-pull-6">RowAColB_pull</div>
</div>
<div class="row">
<div class="col-md-6 col-md-pull-6">RowAColA_pull</div>
<div class="col-md-6 col-md-push-6">RowAColB_push</div>
</div>
</div>
请注意,即使被推的列定义在前面,一旦我们超过 992px 的宽度,它就会出现在最后,而被拉的列,尽管定义在最后,却出现在前面。还要注意,最后一行的内容是什么都没有!这是可以预期的,因为我们正在将一个通常靠左边缘的列完全拉出视图。push 规范对第二列也是如此:它将已经位于右边缘的列完全推到屏幕外。
列的可见性
但是,您可能不仅想重新排序,还想完全隐藏某些列。您可以使用 visible 和 invisible 类来实现这一点
<div class="container-fluid">
<div class="row">
<div class="col-md-6">RowAColA</div>
<div class="col-md-6">RowAColB</div>
</div>
<div class="row">
<div class="col-md-6 visible-md">RowAColA</div>
<div class="col-md-6 ">RowAColB</div>
</div>
<div class="row">
<div class="col-md-6 hidden-md">RowAColA</div>
<div class="col-md-6 ">RowAColB</div>
</div>
</div>
当拉伸和收缩您的浏览器窗口时,请注意这些类的工作方式与我们到目前为止所习惯的不同。到目前为止,xs、md 等的规范行为类似于断点或某种切换:如果浏览器宽度低于断点,我们有一种行为,高于它,我们有另一种行为“无穷无尽”,或者至少直到类中定义的下一个响应式断点。visible 和 hidden 类的工作方式不同:它们指定一个“范围”,从指定符定义的断点(参见上面的表格)开始,直到下一个断点。
因此,hidden-md 指定符会隐藏应用该元素的元素,其宽度从 992px 到 1200px。
剖析复杂的网格系统:它是如何工作的?
剖析嵌套的行
这个很简单:因为如前所述,列的宽度表示为百分比,并且 CSS 将此百分比定义为包含块宽度的百分比。这解释了为什么我们可以将 2 个 col-md-6 嵌套在单个 col-md-6 中
让我们用内联 CSS 来尝试一下
<body>
<div style="background:red;width:50%"> Half the container width: in this case the body tag </div>
<div style="background:orange;width:50%">
<div style="background:green;width:50%"> Half the container width: in this case the orange div tag </div>
<div style="background:blue;width:100%"> Full container width: in this case the orange div tag </div>
</div>
<div style="background:grey;width:50%;border-style:solid">
<div style="background:green;width:50%;float:left"> Half the container width: in this case the grey div tag </div>
<div style="background:blue;width:25%;float:left"> Fourth the container width: in this case the grey div tag </div>
</div>
</body>
这里应该清楚发生了什么
- 第一条红线是第一个 div,宽度为其容器的 50%:body 标签
- 第二行和第三行分别占其容器的 50% 和 100%:橙色 div 本身占其容器(body 标签)的 50%。请注意,橙色 div 如何显示在第二行旁边。这是剩余的 50% 的显示。
- 第四行显示两个 div,它们分别占其父容器(灰色 div)的 50% 和 25%。但是,通过使用 float:left 规范,它们显示在同一行上
剖析重新排序的列
这是一个有趣的问题。pull 和 push 类的定义如下
@media (min-width: 992px) {
.col-md-pull-3 {
right: 25%;
}
.col-md-push-3 {
left: 25%;
}
}
您可能可以猜到这会产生什么结果:
- pull 类告诉您的浏览器将其元素的右边缘设置在其正常位置的特定百分比
- push 类告诉您的浏览器将其元素的左边缘设置在其正常位置的特定百分比
百分比本身与宽度指定符一样,是 100/12 的倍数。这是可以预期的,因为我们仍在 12 列网格中。当然,媒体查询现在应该很熟悉了。
我(再次)隐藏了一些东西:在上面的列表中,我说“其正常位置的特定百分比”。这是如何工作的?嗯,在基础部分,我展示了一些现在很重要的 CSS,但我当时没有引起您的注意
.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
position: relative;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
注意 position 属性的声明:没有这个属性,push 和 pull 类就无法工作。这个“position:relative”声明负责上述句子的“在其正常位置的特定(任何)”部分。还要注意值是“relative”,这很重要,因为它确保了句子的“在其正常位置”部分。请看以下示例
<div style="background:red;width:50%"> Half the container width: in this case the body tag </div>
<div style="background:orange;width:50%">
<div style="background:green;width:25%;left:33%">Fourth width, a Third pushed but nothing happening</div>
<div style="background:blue;width:50%;position:relative;left:33%">Half width, a Third pushed working</div>
</div>
<div style="background:grey;width:50%">
<div style="background:green;width:50%;position:relative;left:33%">Half width, a Third pushed relative</div>
<div style="background:blue;width:50%;position:absolute;left:33%">Half width, a Third pushed absolute</div>
</div>
请注意,在第三个 div 中,带有相对定位的嵌套 div 的行为与 Bootstrap 一样:该 div 定位在其父容器宽度的 33%。但是,第二个 div 定位在浏览器窗口总宽度的 33%。这是由绝对定位的工作原理引起的:它相对于也已定位的父级,如果没有定位的父级,它相对于 body 标签。后者就是上面发生的情况。
剖析列的可见性
Bootstrap 中的可见性有两个类,一个用于使元素可见,一个用于使元素不可见,即隐藏元素。
.visible-xs,
.visible-sm,
.visible-md,
.visible-lg {
display: none !important;
}
@media (min-width: 992px) and (max-width: 1199px) {
.visible-md {
display: block !important;
}
}
@media (min-width: 992px) and (max-width: 1199px) {
.hidden-md {
display: none !important;
}
}
尽管这看起来足够简单,但有几点值得注意
首先,为了隐藏元素,我们使用 CSS display 属性并将其设置为“none”。您可能知道 CSS visibility 属性,它具有类似的功能。但是,visibility 属性允许使用 hidden 值,该值会隐藏应用该属性的元素。但是该元素仍然在页面上占用空间,就好像它是可见的一样。如果我们尝试这样做,我们会得到以下结果
<div style="background:green">
<div style="display:none;">none</div>
<div style="visibility:hidden;">hidden</div>
</div>
请注意,我们看到一个绿色的条形:这是因为隐藏的元素占用了它的空间,尽管它没有渲染。但它占用了空间,也为具有绿色背景的 div 的父元素提供了大小。因此,出现了绿色的条形。
在网格中显示元素是通过将元素的 CSS 属性设置为 block 来完成的。此属性有多种可能性,其中最常用的是 none、block 和 inline。inline 值不会产生期望的效果。但让我先解释另一件事:inline 和 block 元素之间的区别
- Inline 元素:它们在同一行上继续,并占用它们所需的空间。例如 span、img 等...
- Block 元素:它们从新行开始,并占据完整宽度。例如 div、h1、h2、p 等...
CSS display 属性在此混合中增加了使 inline 元素(或多或少)表现得像 block 元素以及反之亦然的能力。这在以下示例中发生
<div style="background:orange">
<div style="background:green;width:25%;display:block">Fourth width, display block</div>
<div style="background:blue;display:inline;width:50%">Half width, display inline</div>
</div>
请注意,带有 inline display 属性的 div 如何只占用它需要的空间。这正是我们不想要的,因此在 Bootstrap CSS 中使用了 display:block。
另一件值得注意的事情是 !important 定义。这可以确保您无法覆盖此 CSS 属性的定义,一旦设置。
<div style="background:grey">
<div class="showit-always">Show it always</div>
<div class="showit hideit">Show it always, unless I hide it</div>
<div class="showit hideit-later">Show it always, unless I hide it later</div>
<div class="showit-always hideit">Show it always, even if I hide it</div>
</div>
请注意,在最后一行,尽管我们将 display 属性设置为 none,该行仍然显示。这是因为 showit-always 类具有 !important 指定符,因此无法覆盖。
历史
版本 1.0:第一个版本
版本 2.0:添加了解释为什么列会变成行而不是堆积在一起