先记住这个答案
不一样,只有 float 能做出文字环绕。float 让元素离开正常流,贴到容器的左边或右边,后面的块元素会当它不存在,但里面的文字行会感知到它,把自己缩短,从它旁边绕过去,图片下面没文字的地方文字又回到全宽。inline-block 没有离开正常流,它就像一个大号字符插在文字行里,最多让这一行变高,下一行照样从最左边开始,所以不会环绕。两者还有几处区别:float 不撑开父容器高度,inline-block 会;inline-block 受 vertical-align 和空白字符影响,float 不受。
float脱离正常流,后面的行盒会缩短绕开它inline-block不让文字环绕- 浮动可能令父容器高度塌陷
- 行内块之间的源码空白会成间隙
同一张图,两种写法的排版
一篇文章配一张图,希望图放在左边,正文绕着图排。
float 和 inline-block 放在一起对比HTML<p>
<img class="pic float" src="a.png" width="120" height="120" />
这里是一大段正文,文字会从图片右边开始排,排到图片底部以下时回到最左边……
</p>
<p>
<img class="pic inline" src="a.png" width="120" height="120" />
这里是另一段正文,只有第一行和图片同行,并且和图片底部对齐……
</p>
<style>
.float { float: left; margin-right: 12px; } /* 文字环绕 */
.inline { display: inline-block; } /* 图片是一个大字符,只占第一行 */
</style>第一段里,图片浮到左边,正文前几行的行盒宽度都被压短,从图片右侧开始排;排到图片底部以下,行盒恢复全宽。这就是杂志式的环绕。
第二段里,图片和第一行文字排在同一行。图片 120px 高,这一行就被撑到 120px,文字默认按基线对齐,贴在图片底部那条线上。第二行文字在图片下面,从最左边开始,图片右侧上方是一大块空白。img 本来就是行内替换元素,写不写 inline-block 效果都差不多。
放到布局里的其它区别
以前没有 Flex 时,float 和 inline-block 都被拿来做横向排列,比如导航菜单、商品列表。这时它们还有几处行为差异,经常被一起问。
- 父容器高度
float元素不参与父容器的高度计算。一个只包含浮动子元素的父容器,高度会塌成 0,背景和边框缩成一条线,要用清除浮动或display: flow-root修复。inline-block在正常流里,父容器会被它撑开,不存在塌陷问题。- 对齐方式
float元素顶部对齐,各自贴着上边排,高度不同也是顶部平齐。inline-block按vertical-align对齐,默认是基线,高度不同的卡片会底部参差不齐,通常要写vertical-align: top。- 空白间隙和居中
- HTML 里标签之间的换行和空格,在
inline-block之间会被渲染成一个空格宽的间隙,float之间没有。反过来,inline-block能用父级的text-align: center整体居中,float只能贴左或贴右,做不到居中。
容易答错的地方
- 以为
float元素完全脱离了文档流 float只是脱离了块级元素的正常流,后面的块盒会占到它下面去,但块盒里的行盒会避开它。文字能环绕,正是因为行盒还感知得到浮动元素。真正完全脱离的是position: absolute,文字会直接被它盖住。- 以为
inline-block加vertical-align: top就能环绕 vertical-align: top只是让图片和第一行文字顶部对齐,文字还是只有一行在图片旁边,第二行照样跑到图片下面。行内排版没有「让后面的行绕开」的能力。- 以为给
float元素设display: inline-block会生效 - 元素浮动后,
display的计算值会被强制转成块级,inline-block算出来就是block。所以同时写这两个没有意义,浮动元素本身就能设宽高。
面试官还会怎么问?
除了 float,还有别的办法做环绕吗?
没有能替代的布局方式,Flex 和 Grid 都不做环绕。但可以在 float 基础上加 shape-outside,比如 shape-outside: circle(50%),让文字沿着圆形而不是矩形边界绕排。它只对浮动元素生效。
现在做横向排列,还该用 float 或 inline-block 吗?
一般不用了。横向排列用 Flex,二维网格用 Grid,它们没有高度塌陷、空白间隙、基线对齐这些历史问题,还有 gap 可以直接控制间距。float 回到了它最初的用途,就是图文环绕。
浮动元素后面的块元素为什么背景跑到图片下面了?
后面的块盒不避让浮动元素,它的盒子从容器最左边开始,背景和边框会延伸到浮动图片的下面,只有里面的文字绕开了。想让整个块盒待在图片旁边,给它加 overflow: hidden 或 display: flow-root 创建 BFC,BFC 的边框盒不会和浮动元素重叠。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。