我们在排版文字的时候,通常会把开头第一个文字/字母放大处理以达到美观的效果。为了实现这个效果,可能你第一时间想到的是使用 ::first-letter 伪元素:
p::first-letter{
font-size: 60px;
}
这样做确实能实现效果,但是如下图所示,第一行的排版受到第一个字母的内容区影响会变得很奇怪,上下行间距都会变得很宽, 解决的办法可以是设置vertical-align: text-bottom 但是上半行距也会变得很奇怪。
更好的解决办法是将::first-letter 伪元素设置为浮动元素,这样就可以让文字环绕在其周围,并且不影响行间距
p::first-letter{
font-size: 60px;
float: left;
}
大多数情况下,浮动被用来作为一种横向布局的方式使用,但是其诞生时被赋予的最初作用其实是"文字环绕"效果, 比如上面的文字环绕大号文字,文字环绕图片等等,只不过当今我们对于网页样式布局的需求从简单的文字图片排版,变成了更加美观,复杂的页面设计,浮动这个最原本的功能也就被忽略了。
由于其本身设计就不是被用来做横向布局的,所以就造成我们在使用浮动布局时需要处理如"塌陷"这样的问题。同时,浮动缺乏弹性,而且容错性很低,很容易在调整一个样式之后造成其他的盒子样式错乱!
如果你想规避浮动在横向布局上的一些天然"缺陷" 可以使用flex grid等更好的方案。
开启浮动&浮动特性
当我们需要一个元素开启浮动时,可以使用属性:
float: left 左浮动 | right 右浮动 | none 不浮动 ( 默认 )
在浮动开启后,元素会脱离文档流,并且"漂浮"到所在父元素的左/右边缘, 但是不会超出父元素的范围
不论元素是块元素还是行内元素,其在开启浮动之后 display变成block,并且类似于行内块元素的特性,即元素的宽高自动包裹其内容的大小,但是可以通过设置width/height改变其大小
浮动元素特性
1. 脱离文档流, 但是不会超出其父容器的范围
2. 浮动元素会开启BFC,形成一块独立渲染的区域
3. 浮动元素之间不会相互重叠,浮动元素无法盖住其他的浮动元素
4. 浮动元素无法超过前面浮动元素的高度,最多只是高度相同
5. 浮动元素上方的块元素如果在文档流内,则浮动元素无法覆盖在其上面
6. 浮动元素下方文档流中的块元素,可以挤占浮动元素原本的位置,会跑到浮动元素下面
7. 浮动元素周围的文字,会形成环绕的效果,不会跑到浮动元素上面 (浮动的原本功能)
浮动元素的范围就是父元素的范围,在浮动的过程中不会超出这个范围
.container{
width: 300px;
height: 350px;
background-color: lightgray;
}
.box{
box-sizing: border-box;
width: 100px;
height: 100px;
border: 1px solid black;
float: left;
}
浮动元素无法超过其上方块元素的高度,无法覆盖其上方的块元素,如下图所示:
但是我们只需要将浮动元素和块元素在html中的顺序调转,让浮动元素在块元素上方,则浮动元素会覆盖块元素,块元素钻到浮动元素下面了,如图:
同时,由于文字会环绕浮动元素周围,所以div元素的文字会移动到右边,我们检查div元素,会发现其左边的下方其实是被盖住了
其实原理也很好理解,浮动元素由于脱离文档流,在文档流中不占据位置,所以其下方的块元素由于在文档流中就一定会挤上来,而由于浮动元素的层叠水平是要更高的,所以会在上面覆盖住div元素。
你可以简单的理解为,文档流就是水面,在文档流中的元素都在水中,而浮动是漂浮在水面上的原木,所以会盖住下面文档流中的元素
![]()
当然,具体的覆盖顺序,你需要了解一下css中的层叠上下文,层叠水平和层叠顺序,这个后面我会写文章具体讲。
浮动作用机制
如何实现文字环绕
说到浮动,父元素高度塌陷是一个绕不开的话题,那么为什么会出现父元素高度塌陷呢,简单来说就是浮动元素脱离了文档流,其在父元素中不占有位置,那么父元素在计算高度的时候,肯定不会将其计算在其中。
我们在使用浮动横向布局的时候,经常需要使用clear或者bfc开解决这个 “bug” 但是这真的是一个 "bug"么?
我们之所以认为塌陷是个bug 是因为我们背离了浮动设计者设计浮动的本质 - 文字环绕
如果做到文字环绕? 如果你是标准制定者,你会如何实现呢?
如图,一张图片,和一片文字,如果想让文字环绕图片,首先需要让文字和图片相邻,而在文档流中的图片占据高度,无法让下方的文字上来。
所以标准的制定者第一步先 简单粗暴的"破坏文档流" 也就是让图片脱离文档流“飘起来” 这样地下的文字就有可以和图片相邻了
脱离文档流之后,文字挤上来,文字和图片就可以相邻了,这也是为什么浮动元素会造成父元素塌陷,因为其为了达到文字环绕的效果,必须先让浮动元素脱离文档流。
所以父元素塌陷这个现象并不是一个 “bug” 而是有意而为之的
如果仅仅让浮动元素脱离文档流,也无法达到文字环绕的效果,如果要达到该效果,更重要的第二部就是,让行框盒子 line-boxes 和 浮动元素 互相不重叠 ,也就是 - 行框盒子和浮动元素的不可重叠性: 行框盒子如果和浮动元素的垂直高度有重叠,则行框盒子在正常定位状态下只会跟随浮动元素,而不会发生重叠!
红框代表右移的行框盒子
用上面例子来看,我们使用:first-line 伪元素标记文字的第一行行框盒子,会发现,行框盒子如果和图片重叠,则行框盒子(红色部分) 会跟随在图片的后面,这样就达到了文字环绕的效果!
需要注意,行框盒子,并不是整段文字所在的盒子,而是每一行文字所在的行框盒子,如图,文字所在的盒子是覆盖了图片元素的 是有重叠的!
如果你对行框盒子 行内盒子 这些概念不是很了解,可以去看看讲vertical-align和line-height的文章!
如果你理解了上面的原理,请思考一个问题:
我们通常使用 clear 或者 BFC来解决父元素高度塌陷的问题,那么如果我干脆给父元素一个高度,这样不就可以直接规避塌陷的问题了吗?
这样确实可行,但是给父元素多少高度呢,如果我让父元素的高度和图片元素高度相等 可以吗?
看下面的例子:
<style>
* {
padding: 0px;
margin: 0px
}
img {
height: 100px;
float: left;
}
.float {
float: left;
}
.container {
background-color: lightblue;
height: 100px;
}
</style>
<div class="container">
<div class="float">
<img src="../assets/avaters/avater2.webp" />
</div>
</div>
设置图片的高度为 100px 父元素的高为100px 这样看上去确实可以,如下图,父元素由于设置了高度也不会出现塌陷的问题
但是这样做可能会对容器外的元素造成影响, 比如,我在container元素后价一行文字
<div class="container">
<div class="float">
<img src="../assets/avaters/avater2.webp" />
</div>
</div>
<span>我在容器外,但是我也环绕图片了!</span>
其效果如下:
为什么在容器外的span元素,也受影响了呢? 其实看懂了上面环绕原理之后,你大概能猜出来,因为span的行框盒子,和图片发生重叠了!
但是为什么会重叠,图片被高为100px的容器包裹着啊! 但是其实不是,我们检查元素就可以发现,img外层的float元素高度并不是100px 而是105px
如果你看过我写的vertical-align和line-height 你就会立刻明白,因为img元素为替换元素,默认是baseline对其,而替换元素的baseline为其底边,所以导致其下方还有部分的空间,我们加一个小些字母xxjjgg就更清晰了!
所以,float的高度并不是内部img的高度100px 而是考虑到了极限对齐后的105px,需要解决也很简单,可以给float设置一个高度 100px 或者让图片底部对齐 即可!
浮动锚点和浮动参考
浮动,是以谁为基准浮动呢,我们看一个例子:
<style>
.container {
background-color: lightgray;
width: 400px;
}
a {
float: right;
}
</style>
<p class="container">
"He has been able to put Ghana on the map when it comes to art," she said.
<a href="xxx">更多..</a>
</p>
我们在文字中加上一个右侧浮动的a标签,那么这个标签应该在第一行,还是第二行呢?
其效果如图所示,为什么会在第二行呢,这就需要介绍浮动的两个概念 浮动锚点和浮动参考
先说浮动参考,浮动参考指的是浮动元素对齐参考的实体,而这个实体,就是当前浮动元素所在的行框盒子,上述例子,由于换行导致a标签在第二行的行框盒子所在位置,所以其将第二层的行款盒子作为浮动参考,并且向右浮动。
浮动锚点是什么? 当浮动元素夹在块元素之间,这时候不存在行框盒子,此时浮动锚点就发挥作用,浮动锚点在文档流中,可以看成是一个没有margin border padding的空inline元素,其作用就是创建一个浮动参考,这样依旧可以浮动。
为什么浮动无法超过上面的块元素,因为其浮动锚点在块元素下面,浮动参考也就是块元素下面的行框盒子!
消除浮动造成的影响
浮动在创造之初就不是拿来做定位的,我们在试用其定位的同时,需要消除掉一些影响
其主要影响就是脱离文档流,导致
- 浮动元素的父元素会发生塌陷
- 浮动元素下面的块元素会被覆盖
解决办法一般有两种 clear 清除浮动 和 BFC
clear
clear的本意不是清除浮动,浮动并没有被清除,其作用是:
不让设置clear的元素和上方浮动元素相邻
clear可以设置
- left: 不让设置clear的元素和上方左浮动的元素相邻
- right: 不让设置clear的元素和上方右浮动的元素相邻
- both: 不让设置clear的元素和上方左右浮动元素相邻
需要注意,clear属性只在块元素才生效!
我们通常结合 ::after伪元素在父元素最后,增加一个元素并且设置clear
<style>
.float{
width: 200px;
height: 200px;
background-color: lightcoral;
float: left;
}
.container{
background-color: lightgray;
}
.container::after{
content: '';
/* clear必须在块元素才生效 */
display: block;
clear: both;
}
</style>
<div class="container">
<div class="float"></div>
</div>
使用:after 在container的最后,增加一个子元素,并且设置浮动,需要注意,::after伪元素默认为行内元素,需要设置为块元素!
设置之后,由于最后的元素不能和浮动元素相邻,所以只能在浮动元素后面,自然也就把父元素高度撑起来了,如下图:
一般情况下,both很常用,right left的使用场景不多,我比较愿意将其来理解为 抗左浮动和抗右浮动,其一大作用是可以实现左边多块 宽度固定 右侧自适应的布局
将 头像部分设置成左浮动,绿色部分设置为左抗浮动且左浮动,这样绿色部分不能和头像部分相邻,就只能在下面了,右边元素在文档流中,会挤上去。
设置父元素为BFC
BFC 可以当成是一块独立的渲染区域,标准规定,在这个独立的渲染区域内的浮动元素的高度,会被计算进BFC元素的高度,同时BFC元素不会和浮动元素重叠。
所以我们可以将外层容器设置 overflow: hidden , display: flow-root 等 将外层容器设置为BFC 从而将内部的浮动元素计算到其高度中,解决塌陷的问题
<style>
.float{
height: 200px;
width: 200px;
border: 1px solid black;
background-color: lightgreen;
float: left;
}
.container{
background-color: lightcoral;
display: flow-root;
}
</style>
<div class="container">
<div class="float"></div>
</div>
<span>HELLOW</span>
由于container是BFC,所以内部的float元素的高度会被计算在container的高度内,解决了塌陷问题,如下:
BFC 同样可以解决float重叠的问题,看下面例子
<style>
.float {
height: 200px;
width: 200px;
border: 1px solid black;
background-color: lightgreen;
float: left;
}
.hellow {
background-color: lightcoral;
display: flow-root;
}
</style>
<div class="float"></div>
<div class="hellow">HELLOW</div>
给浮动元素下方的HELLO元素设置display: flow-root开启 BFC
此时可以看到 HELLO所在的div元素 并没有被浮动元素覆盖,我们只需要设置其宽度 100% 即可让其在浮动元素下面