float 属性最初只是用于浮动图像内的文本块,但是现在它已成为在网页上创建多列布局的最常用工具之一。本文将阐述它的有关知识。

要求: HTML基础知识(学习入门 HTML),和CSS的工作理念(学习 入门 CSS)。
摘要: 学习如何创建浮动特性,比如首字下沉、浮动图像,和多个列在网页布局。

背景知识

最初,引入 float 属性是为了能让 web 开发人员实现简单的布局,包括在一列文本中浮动的图像,文字环绕在它的左边或右边。你可能在报纸版面上看到的东西。

但 Web 开发人员很快意识到,它可以浮动任何东西,而不仅仅是图像,所以浮动的使用范围扩大了。之前的 fancy paragraph example 的课程展示了如何使用float创建一个有趣的drop-cap(首字下沉)效果。

现在,浮动通常用来创建整个网站布局,其中包括浮动的多列信息,因此它们彼此并排放置(默认行为是列彼此之间的排列顺序与它们在源中显示的顺序相同)。虽然有更新的更好的布局技术可用,但我们将在本模块的后面探讨,浮动仍然是最受喜欢的老物,因为它们可以支持到 Internet Explorer 4。

简单的例子

让我们来探讨如何使用浮动。我们将从一个非常简单的例子开始,包括在图像周围浮动一个文本块。你可以跟随在你的电脑上创建新的 index.html 文件,以填充它 simple HTML template, 以下代码插入它在适当的地方。底部的部分你可以看到一个它应该是什么样子的例子。

首先,我们写一些简单的HTML——添加以下到HTML的<body>内,删除之前<body>里面的东西:

<h1>Simple float example</h1>

<img src="butterfly.jpg" alt="A pretty butterfly with red, white, and brown coloring, sitting on a large leaf">

<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p>

<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>

现在将以下CSS应用到您的HTML (使用一个<style> 元素或一个<link> 到一个单独的 separate .css 文件 — 你来选择):

body {
  width: 90%;
  max-width: 900px;
  margin: 0 auto;
}

p {
  line-height: 2;
  word-spacing: 0.1rem;
}

如果你现在保存并刷新,你会看到和你预期的效果差不多——图片坐落在文本的上方,使得目前看起来有点丑陋。我们可以让图片在它的容器内居中,但是这里,我们将使用float来让图片周围的文本浮起来。将以下规则添加到你之前的规则下面:

img {
  float: left;
  margin: 0 30px 0 0;
}

现在,如果您保存和刷新,你会看到类似下面的东西:

因此,让我们考虑一下float是如何工作的——浮动元素 (这个例子中的<img> 元素)会脱离正常的文档布局流,并粘贴到其父容器的左侧 (这个例子中的<body>元素)。在正常布局中位于该浮动元素之下的内容,此时会围绕着浮动元素,填满其右侧的空间。

注意,浮动内容仍然遵循盒子模型诸如边缘和边界。我们设置一下图片右侧的外边距就能使得右侧的文字不会紧贴着图片。

向右浮动的内容是一样的效果,区别就是元素会浮动到右侧去,而其他内容将从左侧环绕它。尝试将上一个例子中的浮动值改为 right ,再把 margin-right 换成 margin-left ,看看结果是什么。

在看我们的首字下沉例子

如上所述,我们的 fancy paragraph example 从早先的课程精选了一个漂亮的首字下沉。在这个例子中,我们有一个简单的段落:

<p>This is my very important paragraph.
 I am a distinguished gentleman of such renown that my paragraph
 needs to be styled in a manner befitting my majesty. Bow before
my splendour, dear students, and go forth and learn CSS!</p>

我们的CSS看起来像这样:

p {
  width: 400px;
  margin: 0 auto;
}

p::first-line {
  text-transform: uppercase;
}

p::first-letter {
  font-size: 3em;
  border: 1px solid black;
  background: red;
  float: left;
  padding: 2px;
  margin-right: 4px;
}

结果如下:

这里的效果与我们在图像的第一个例子中所做的没有很大的不同,但是这一次,我们在信中的第一个字母后面的其余部分是浮动的,在使这封信看起来显得又大又大胆又有趣之后。

你可以漂浮任何的东西,只要有两个项目的空间,以配合在一起。这使我们很好地谈论多列布局。

多列浮动布局

Floats通常用于创建多个列布局,并且由于其广泛的浏览器支持已经有相当一段时间。尽管事实上,他们不是真的打算这个工作,并有一些奇怪的副作用,必须处理,你会在后面的文章中看到。

两列布局

让我们先从最简单的例子,一个两列布局。您可以通过创建一个新的 index.html 文件在您的计算机上,用simple HTML template填充它, 并在适当的地方插入下面的代码。在该部分的底部,您可以看到一个活生生的例子,什么样的最终代码应该看起来像。

首先,我们需要一些内容放入我们的列。使用以下内容替换正文中的任何内容:

<h1>2 column layout example</h1>
<div>
  <h2>First column</h2>
  <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p>
</div>

<div>
  <h2>Second column</h2>
  <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
</div>

每个列都需要一个外部元素来包含其内容,并让我们一次操作它的所有内容。在这个例子中,我们选择了<div>但,你可以选择更多语义合适的东西<article>s, <section>s, 和<aside>,诸如此类。

现在为CSS将以下内容应用到HTML以提供一些基本设置:

body {
  width: 90%;
  max-width: 900px;
  margin: 0 auto;
}

在宽度达到900px之前,整个视图的宽度将达到90%,在超过900px后,它将保持在这个宽度,并在viewport中居中。默认情况下,子元素(这个<h1> 和两个 <div>)将跨越整个body宽度的100%。如果我们希望将两个<div>放在一起,那么我们需要将它们的宽度设置为父元素的宽度的100%,或者更小,这样它们就可以彼此匹配。将下面的内容添加到CSS的底部:

div:nth-of-type(1) {
  width: 48%;
}

div:nth-of-type(2) {
  width: 48%;
}

在这里我们设置了他们的父亲的宽度的48% —— 这总计96%,留下我们4%自由作为两列之间的沟槽,给内容一些空间呼吸。现在我们只需要浮动列,像这样:

div:nth-of-type(1) {
  width: 48%;
  float: left;
}

div:nth-of-type(2) {
  width: 48%;
  float: right;
}

把这些结合在一起应该跟我们结果一样:

你会注意到,我们使用所有宽度的百分比——这是一个很好的策略,因为它创建一个liquid layout(流式布局),一种调整为不同的屏幕尺寸,并在较小的屏幕尺寸下保持相同的列宽度比例。请尝试调整浏览器窗口的宽度,以便自己查看。这是响应式网页设计的一个有价值的工具,我们将在以后的模块中讨论。

注意:你可以看到这个例子运行在 0_two-column-layout.html (参见 the source code).

需要注意的一件事是,当它们变得非常窄时,列就会变得很糟糕。切换回窄屏幕的单一列布局通常是有意义的(如手机)),使用媒体查询可以实现这一功能。再一次,你们将在未来的响应式网页设计模块中学习这些知识。

The other option would be to set the widths to a fixed unit like rems or pixels — you can see an example at two-column-layout-fixed.html (see source code), or convert your own example by removing the max-width declaration, and changing the widths to 900px430px, and 430pxrespectively. This is called a fixed-width layout — if you adjust your browser size now, you will see that the layout no longer adjusts to suit the viewport width, and you'll need to scroll to see it all at smaller sizes.

另一种选择是将宽度设置为一个固定的单位如rem或px——你可以看到一个例子two-column-layout-fixed.html (see source code),或者通过删除max-width 声明来转换您自己的示例,并改变各个宽度为 900px430px和 430px。这就是fixed-width layout(固定宽度布局)——如果您现在调整浏览器大小,您将看到布局不再调整以适应视图宽度,您将需要滚动来查看它的全部。

现在我们将用流体布局。

三列布局

你已经有了一个两列布局工作,添加一个第三列(或更多)并不是太难。你只需要添加另一个列在同一个父元素。开始通过添加以下 <div>就在另外两个后面(或使用 0_two-column-layout.html 作为开始):

<div>
  <h2>Third column</h2>
  <p>Nam consequat scelerisque mattis. Duis pulvinar dapibus magna, eget congue purus mollis sit amet. Sed euismod lacus sit amet ex tempus, a semper felis ultrices. Maecenas a efficitur metus. Nullam tempus pharetra pharetra. Morbi in leo mauris. Nullam gravida ligula eros, lacinia sagittis lorem fermentum ut. Praesent dapibus eros vel mi pretium, nec convallis nibh blandit. Sed scelerisque justo ac ligula mollis laoreet. In mattis, risus et porta scelerisque, augue neque hendrerit orci, sit amet imperdiet risus neque vitae lectus. In tempus lectus a quam posuere vestibulum. Duis quis finibus mi. Nullam commodo mi in enim maximus fermentum. Mauris finibus at lorem vel sollicitudin.</p>
</div>

现在更新你的CSS如下:

body {
  width: 90%;
  max-width: 900px;
  margin: 0 auto;
}

div:nth-of-type(1) {
  width: 36%;
  float: left;
}

div:nth-of-type(2) {
  width: 30%;
  float: left;
  margin-left: 4%;
}

div:nth-of-type(3) {
  width: 26%;
  float: right;
}

这将给我们以下结果:

这里的情况非常少我们之前没有见过;唯一真正的区别是我们有了这个额外的列——为了让它放到合适的位置我们已经把它放在左边了;我们还给了它一个4%的 margin-left,来在第一和第二列之间创建一个沟。我们设置了列的宽度以便它们都能匹配——36% + 30% + 4% + 26% = 96%,在第二和第三列之间留下一个4%的余数。(这个自然沟总是出现在左浮动和右浮动的列之间,无论在哪里。)

这里需要注意的一点是,您必须仔细考虑将列放在什么位置,以及如何浮动它们,以获得所需的结果。你的内容应该是有意义的,当你阅读它的源代码和它的视觉布局的时候;但是,使用浮动可以使可视化布局与源顺序不同。来说明我们的意思,尝试改变第二列的 float值为 right (或者看一看three-column-layout-wrong-order.html (源码))你会看到现在的视觉顺序是这样的:

div1  div3  div2

这是因为第二个<div>源代码顺序上比第三个<div>等级要高 (DOM上第二个<div>先出现并声明了float: right;) ,所以在浮动顺序上也会比第三个<div>等级要高。又因为两者同时像右浮动,第二个<div>就会更加地靠右。

然而视觉受损的人使用屏幕阅读器来听你的内容,仍然会听到这个顺序的内容:

div1 div2 div3

内容布局和样式对它们没有影响。无论用户如何消费,内容都应该是合理的。

注意:完成了这一点您可以找到的例子1_three-column-layout.html (see source code).

清除浮动

现在你已经知道了关于 float 属性的一些有趣事实,不过你很快就能够碰到一个问题——所有在浮动下面的自身不浮动的内容都将围绕浮动元素进行包装,如果没有处理这些元素,就会变得很糟糕。为了说明我们的意思,尝试在第三个<div> 元素下面添加以下HTML(并检查 2_float-disaster.html (source code)):

<footer>
  <p>&copy;2016 your imagination. This isn't really copyright, this is a mockery of the very concept. Use as you wish.</p>
</footer>

You'll see that the footer is wrapping around the space beside the longest column, which looks awful — we really want the footer to stay at the bottom, below all the columns. Well, fortunately there's an easy way to solve this problem — theproperty. When you apply this to an element, it basically says "stop floating here" — this element and those after it in the source will not float, unless you apply a new float declaration to another element later on.

你会看到页脚在最长的列旁边环绕着,这看起来很糟糕——我们希望页脚保持在底部,在所有的列下面。幸运的是,有一种简单的方法可以解决这个问题—— clear 属性。当你把这个应用到一个元素上时,它主要意味着"停止在这里浮动"——这个元素和后面源码中的那些元素将不会浮动,除非您稍后将一个新的float声明应用到另一个元素。

所以,要解决我们的问题,添加以下规则到您的CSS:

footer {
  clear: both;
}

这将会给你一个页脚,它会在你的列下面,就像它应该做的那样:

clear 可以取三个值:

  • left:停止任何活动的左浮动
  • right:停止任何活动的右浮动
  • both:停止任何活动的左右浮动

你通常只想设定一个 clear: both 在你想让浮动停止的元素上。在某些情况下,你会想要取消left 或 right 引号。

注:你可以在这个阶段找到例子 2a_fixed-by-clear.html (see source code).

浮动问题

以上部分提供了使用浮动创建简单布局的基础,但是还有一些问题需要解决。 让我们谈谈这些问题。

整个宽度可能难以计算

到目前为止,我们的例子是没有应用样式的浮动框——这很容易。当你开始给这些框加上样式时,比如 borders, padding 等等,问题就来了。为了更好了解这个问题,可以将下面的 CSS 加入到你的代码里 (你也可以看这个例子 3_broken-layout.html (source code)):

div, footer {
  padding: 1%;
  border: 2px solid black;
  background-color: red;
}

此时,您将看到您的布局已损坏 —— 由于padding和border引入的额外宽度,三列不再适合一行,因此第三列下降到另外两列。

我们有很多方法可以解决上面的问题,但最好的方法是给你的html加上下面的css。

* {
  box-sizing: border-box;
}

box-sizing 将我们box的width的计算方式变为了content + padding + border,而不是之前的content的width,所以当我们增加padding或border的width时,我们不会增加我们box的width。相反我们的content的width会缩小padding或border增加的宽度。

我们有另一个问题——页脚正压在最长列上, 在这一点并不理想——我们来试着通过给页脚一些 margin-top 和它的clearing来解决这个问题:

footer {
  clear: both;
  margin-top: 4%;
} 

然而,这不起作用 ——floated元素在某些方面表现相当奇怪,它存在于正常的文档布局流程之外:

  • 首先,他们在父元素的有效高度为0 ——尝试在浏览器中加载 1_three-column-layout.html 并查看 developer tools 检查 <body> 的高度,你将会看到并明白我们的意思——body报告的高度只有 <h1> 的高度 。这个可以通过很多方式解决,但是我们所依赖的是在父容器的底部清除浮动,如我们在我们的当前示例所做的那样。 如果在当前示例中检查body的高度,您应该会看到它的高度本身。
  • 其次,你不能使用非浮动元素的边距来在它们和浮动元素之间创建空间——这是我们在这里眼前的问题,我们将在下面实施修复。
  • 还有一些关于浮动的奇怪的事情——Chris Coyier的所有关于Floats文章概述了其他一些以及修复这些。

所以,让我们解决这个! 首先,在HTML的代码里添加,新的<div> 元素,在<footer>标签的上方:

<div class="clearfix"></div>

如果您没有一个可用的元素来清除您的浮动(比如我们的页脚),在您想要清除的浮动之后添加一个看不见的“clearfix div”是非常有用的,但是在这里也很有用。接下来我们要做的是,把 clear: both; 声明将我们的页脚样式化的规则移走,并将其放在clearfix div中:

.clearfix {
  clear: both;
}

We have a nice top margin on our footer now, but we also have another problem — the clearfix div is being given the same background, padding and border as our columns and the footer! To fix this, let's first give each of our column divs a class of column:

我们现在有一个很好的顶部边缘,但也有另一个问题——clearfix div被赋予了相同的背景,内边距和边框作为我们的列和页脚!为了解决这个问题,让我们先给每个column divs一个classcolumn

<div class="column">
  ...
</div>

 现在将框样式改变规则,让我们应用到div和footer,这样只有column divs被样式化:

.column, footer {
  padding: 1%;
  border: 2px solid black;
  background-color: red;
}

这只是为了现在解决它。

注: 查看在这个阶段最后一个解决的例子4_fixed-layout-border-box.html (source code)。

Another small point to note here is that box-sizing works as far back as Internet Explorer 8 — if you explicitly need to support older browsers, you may need to adjust the column widths manually to allow for the padding and border widths. This is not a very exact technique, especially considering that you can't size borders using percentages — you just need to allow enough space while filling the parent width as much as possible. You can see such a fix in action in fixed-layout-adjusted-percentages.html (see source code).

这里要注意的另一点是,box-sizing 大小可以追溯到Internet Explorer 8——如果您明确需要支持较老的浏览器,您可能需要手动调整列的宽度,以允许内边距和边框宽度。这不是一种非常精确的技术,特别是考虑到你不能用百分比来确定边界——你只需要在尽可能多地填充父宽度的同时留出足够的空间。你可以在操作中看到这样的修复fixed-layout-adjusted-percentages.html (见源代码)。

浮动项目的背景高度

到目前为止,我们建好的示例是有效的,但另一个问题是列高度是不同的—— 如果列都是相同的高度,它看起来会更好。

我们可以通过给所有的列固定height 来解决这个问题(see 5_fixed-height-columns.html (源代码):

.column {
  height: 550px;
}

然而在许多情况下这并不理想——它使设计呆板。如果你能保证列中总是有相同数量的内容,这是可以的,但这并不总是如此——在很多类型的网站上,内容也会定期更改。

这正是像flexbox这样的新布局技术所解决的问题。Flexbox可以自动地延长列,这样他们就会像最长的一列一样。

你也可以考虑:

  1. Setting the background color of the columns to the same as the background color of their parent, so you can't see that the heights are different. This is the best other option at the moment.
  2. Setting them to a fixed height and make the content scroll using overflow (see our section on overflow for an example.)
  3. Using a technique called faux columns — this involves taking the background (and borders) off the actual columns, and drawing a fake background on the column's parent element that looks like the column backgrounds. Unfortunately, this wouldn't be able to handle the column borders. See Faux Columns for more information on this.
  1. 将这些列的背景颜色设置为父类的背景颜色,这样您就不会看到高度是不同的。
    这是目前最好的选择。
  2. 将它们设置为固定的高度,并使内容滚动overflow (参见我们的示例。)
  3. 使用一种叫做faux columns(伪列)的技术——这包括将背景(和边框)从实际的列中提取出来,并在列的父元素上画一个假的背景,就像列的背景一样。不幸的是,这将无法处理列边框。 详见对于伪列伪列流体布局的教程。

清除浮动会变复杂

The clearing in the simple example we've built up over the course of the article is easy to understand, but clearing can become a lot more complex as the layout becomes more complex. You need to make sure that any floats are cleared as soon as possible to avoid them making trouble for the content lower down. Use clearfix divs where necessary, if you haven't got a convenient container to put the clearing on.

我们在文章中建立的简单例子很容易理解,但是当布局变得更加复杂清理也会变得更加复杂。你需要确保所有的浮动都能尽快清除,以避免它们给内容带来麻烦。如果您没有一个方便的容器来进行清理,那么在必要的时候使用clearfix div。

总结

现在,您应该已经拥有了一些强大的工具来创建相当复杂的web布局。太好了!在下一篇文章中,我们将进一步研究定位。

文档标签和贡献者

 此页面的贡献者: Froggy, Code-Dmit, Barren, Wantian, WJoan, Ende93, 1986slayer, xuqisheng
 最后编辑者: Froggy,