CSS浮动
本文最后更新于 2025年8月2日 下午
Demo:https://github.com/xuekeven/learn_web/blob/main/dome/CSS/浮动.html 。
浮动
Flexbox 正在迅速取代浮动在页面布局中的地位。对新手开发人员而言, Flexbox 的行为很直观,可预测性更好。你可能会问是否还有必要学习浮动,CSS 浮动的时代是不是结束了?
在现代浏览器中,不用浮动也能比过去更好地实现布局,甚至可以完全弃用浮动。但是如果要支持 IE 浏览器,现在放弃浮动还为时过早。只有 IE10 和 IE11 支持 Flexbox,而且还有一些 bug。如果不想碰到 bug,或者需要支持旧版浏览器,浮动也许是更好的选择。另外,如果你在支持旧代码库,它很可能用到了浮动布局。为了维护旧代码,也需要了解浮动的工作原理。还有一点,浮动布局通常不需要那么多的标记,新的布局方法则需要添加额外的容器元素。如果你写样式时不允许修改标记,浮动更能满足你的需求。
此外,要实现将图片移动到网页一侧,并且让文字围绕图片的效果,浮动仍然是唯一的方法。
理解浮动
浮动是网页布局最古老的方式,并且在过去很多年都是唯一的方式。不过,它有些让人捉摸不透。要想理解浮动,得从了解它的设计初衷入手。
在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,效果与印刷排版中的文本环绕相似。
浮动能将一个元素(通常是一张图片)拉到其容器的一侧,这样文档流就包围它。浮动元素会被移出正常文档流,并被拉到容器边缘。文档流会重新排列,但它会包围浮动元素此刻所占据的空间。如果让多个元素向同侧浮动,它们就会挨着排列。
浮动本身不是为了实现页面布局而设计的,但是在近 20 年的时间里,我们把它当成了布局工具。之所以这样做是因为它是那个年代唯一的选择。后来,display: inline-block 和 display: table 的问世才让我们有了别的方案,尽管二者可替代的场景有限。Flexbox 和网格布局最近几年才出现,在它们出现之前,浮动一直承担着页面布局的重任。
通常最简单方式是先将网页的大块区域布局好,再逐级布局内部的小元素。在开始浮动元素前,要先将网页的外层结构样式写好。
浮动问题
浮动有一些行为会让人措手不及。这些并不是 bug,而是因为浮动严格遵循了标准。
容器高度塌陷
浮动元素不同于普通文档流的元素,它们的高度不会加到父元素上。这可能看起来很奇怪,但是恰好体现了浮动的设计初衷。浮动是为了实现文字围绕浮动元素排列的效果。在段落里浮动图片时,段落的高度并不会增长到能够容纳该图片。就是说,如果图片比段落文字高,下一段就会直接从上一段的文字下面开始,两段文字都会围绕浮动的图片排列。
清除浮动
解决包含浮动问题的做法,叫作清除浮动。有两个思路:使用 clear 属性和创建 BFC。
clear 属性
一是使用跟浮动配套的 clear 属性。将一个元素放在主容器的末尾并对它使用 clear,这会让容器扩展到浮动元素下面。clear 属性只对块级元素生效,clear: both
声明能让元素移动到浮动元素的下面而不是侧面,clear 也可以设为 left 或 right,但这样只会相应清除向左或向右浮动的元素。因为使用 clear 属性的元素本身没有浮动,所以容器就会扩展直到包含使用 clear 属性的元素,因此也会包含该元素上面的浮动兄弟元素,这样便解决了容器高度塌陷的问题。
普通版
要给包含浮动的元素使用 clear 属性,即浮动元素本身或包含浮动元素后面的兄弟元素,而不是给别的元素。可以分为三种情况:
如果浮动的元素后面有兄弟元素
设兄弟元素为块级元素并使用 clear 属性。如果浮动的元素是最后一个元素,后面没有兄弟元素
将一个空的块级元素放在浮动元素的父元素容器的末尾,并对空的块级元素使用 clear 属性。这种方法能实现预期行为但是不雅:要在 HTML 里添加不必要的标记,才能实现本应该由 CSS 实现的效果。如果浮动的元素是最后一个元素,后面没有兄弟元素,但不想用额外的元素
使用伪元素:对伪元素使用 clear 属性并设伪元素为块级元素或行内块级元素。使用 ::after 伪元素选择器,可以快速地在 DOM 中在容器末尾添加一个元素,而不用在 HTML 里添加标记,推荐该方法。注意,伪元素选择器生效显示需要添加 content 属性。
修改版
普通的清除浮动可能还有一个一致性问题没有解决:浮动元素的外边距并不会折叠到清除浮动容器的外部,非浮动元素的外边距则会正常折叠。因此,建议使用伪元素的一个修改版,它能够包含所有的外边距,这样更符合预期。
在修改版中,设置块级元素时改用display: table
而不用display:block
。而且是给 ::before 和 ::after 两个伪元素都加上这一属性(但还是只对 ::after 用clear: both
)。这样,容器所有子元素的外边距都会包含在容器的顶部和底部之间。当我们不想要外边距折叠时,此版本非常有用。
在清除浮动时使用display: table
能够包含外边距,是利用了 CSS 的一些特性。创建一个 display: table
元素,也就在元素内隐式创建了一个表格行和一个单元格。因为外边距无法通过单元格元素折叠,所以也无法通过设置了display: table
的伪元素折叠。
看起来似乎使用display: table-cell
也能达到相同的效果,但是 clear 属性只对块级元素生效。表格是块级元素,但单元格并不是。因此,clear 属性无法跟display: table-cell
一起使用。所以要用 display: table
来清除浮动,同时利用隐式创建单元格来包含外边距。
创建 BFC
浮动元素“陷阱”
如果众多的元素浮动到同一侧,如果每个浮动盒子的高度不一样,最后的布局可能会千变万化。同理,改变浏览器的宽度也会造成相同的结果,因为这样会导致换行,从而改变元素高度。
想修复这个问题很简单:清除浮动元素上面的浮动。更通用的做法是,清除每行上的首个元素上面的浮动。设置好每行的盒子个数后可以用伪类选择器 nth-child() 选中这些目标元素。
这种清除每行浮动的技术要求知道每行有几个元素。若宽度不是通过百分比来定义的,那么随着视口宽度的改变,每行的元素个数可能会变化。这种情况下最好用别的布局方案,比如 Flexbox 或者 inline-block 元素。