本文涉及Css基础内容较多,(包含盒模型、文档流、浮动、定位)可以选择性阅读。
视觉格式化模型就是指页面中多个盒子(即盒模型)的排列规则,在了解视觉格式化模型前,先重温下盒模型。
盒模型
当对一个文档进行布局的时候,浏览器的渲染引擎会根据标准之一的 CSS 基础框盒模型,将所有元素表示为一个个矩形的盒子
盒模型由内到外的构成:content、padding、border、margin
![](https://i-blog.csdnimg.cn/blog_migrate/0726ffc687446644775ad0ae14bd053e.png)
.box {
height: 100px;
width: 100px;
margin: 20px;
padding: 30px;
border: 10px solid rgb(70, 9, 127);
background-color: blueviolet;
}
![](https://i-blog.csdnimg.cn/blog_migrate/ad4ac230eb40e1882b236c35a6be3140.png)
蓝色区域为content即内容区域,通过width、height设置;
绿色区域为padding即内边距区域,通过padding设置;
黄色区域为border即边框区域,通过border设置;
橙色区域为margin即外边距区域,通过margin设置;
盒模型有两种:标准盒模型和怪异盒模型(IE盒模型)
标准盒模型:content + padding + border + margin(width为content的宽度,height同)
上述紫色正方形就是标准盒模型。
怪异盒模型(IE盒模型):content + padding + border + margin(width为content+padding + border 的宽度,height同)
可以通过box-sizing: border-box将标准盒模型转换为怪异盒模型,默认状态下都为标准盒模型。
![](https://i-blog.csdnimg.cn/blog_migrate/80864cc9eb71ca735ed875cba23ccca5.png)
.box {
height: 100px;
width: 100px;
margin: 20px;
padding: 30px;
border: 10px solid rgb(70, 9, 127);
background-color: blueviolet;
box-sizing: border-box;
}
![](https://i-blog.csdnimg.cn/blog_migrate/0960a5e8d9509904e5c2de11a37bce62.png)
将标准盒子转换为了怪异盒子,由width = content+padding + border可知,content = 100 - (30 + 10)*2 = 20(实验时,需要将系统设置的缩放与布局改为100%)
![](https://i-blog.csdnimg.cn/blog_migrate/e9b1844e6c48886d0be0115d7f865a80.png)
视觉格式化模型就是指页面中多个盒子(即盒模型)的排列规则,大致可分为3种:文档流、浮动、定位
文档流(常规流)
所有元素默认情况下都属于文档流。规则:块元素独占一行,行元素多个占一行。
包含快:包含其他盒子的块称为包含块,其决定了内部盒子的活动范围。
文档流下的一些小规则:
1 %:padding、width、margin如果以%作为长度单位,那么都是相对于包含快的宽度大小;height如果以%作为长度单位,那么是相对于包含快的高度大小。
![](https://i-blog.csdnimg.cn/blog_migrate/bef1d52a8df344f98b2420eba2c2465f.png)
outer即为inner的包含块,inner内部设置的%都符合上述规则
.outer {
height: 100px;
width: 100px;
background-color: blueviolet;
color: #fff;
}
.inner {
margin-left: 10%;
width: 50%;
height: 50%;
background-color: rgb(51, 11, 88);
color: #fff;
}
2 外边距合并
当两个margin重叠时,取margin最大的为有效值,而非相加,常见场景有相邻盒子、父子盒子
以父子盒子举例:
![](https://i-blog.csdnimg.cn/blog_migrate/a5176734e50e9c9dfd9dd0815dbcb2c8.png)
.outer {
margin-top: 40px;
height: 100px;
width: 100px;
background-color: blueviolet;
}
.inner {
margin-top: 20px;
width: 50%;
height: 50%;
background-color: rgb(51, 11, 88);
}
解决办法,让margin不相邻即可,可以通过给父元素加border或者改成使用padding即可
![](https://i-blog.csdnimg.cn/blog_migrate/da54c3f070a60cc816553ff0a2ef7d00.png)
border写法
.outer {
margin-top: 40px;
height: 100px;
width: 100px;
background-color: blueviolet;
border: 1px solid #fff;
}
.inner {
margin-top: 20px;
width: 50%;
height: 50%;
background-color: rgb(51, 11, 88);
}
padding写法
.outer {
margin-top: 40px;
height: 100px;
width: 100px;
background-color: blueviolet;
padding-top: 20px;
}
.inner {
width: 50%;
height: 50%;
background-color: rgb(51, 11, 88);
}
3 width、height、margin的auto属性
水平方向(width、margin):
假如没有给子盒子定义宽度,如下:
.outer {
height: 100px;
width: 100px;
background-color: blueviolet;
}
.inner {
height: 50%;
background-color: rgb(51, 11, 88);
}
![](https://i-blog.csdnimg.cn/blog_migrate/93fb49dc7461ab83402f432415516889.png)
子元素的width会自动撑满父元素内部宽度,因为width默认值为auto,auto在这里的意思是"占用剩余全部空间"。如下,是子元素盒模型。可以看出子元素width等于父元素的width。
![](https://i-blog.csdnimg.cn/blog_migrate/fa64e1cc8aa2072e50fc270600a4ecc8.png)
margin默认值是0,但是给margin设置auto属性,也是起到"占用剩余全部空间"的作用。
常见margin: 0 auto居中原理
.outer {
height: 100px;
width: 100px;
background-color: blueviolet;
}
.inner {
width: 50px;
height: 50%;
background-color: rgb(51, 11, 88);
margin-right: auto;
margin-left: auto;
}
![](https://i-blog.csdnimg.cn/blog_migrate/603e0ac01597c781d231a4416786bc9e.png)
给子盒子设置了左右margin为auto属性,那么默认的它们会占用剩余空间,并且是公平占用,即实现了水平方向居中,这种居中方式是块级元素的。
![](https://i-blog.csdnimg.cn/blog_migrate/f0a711bebed1e8191b3ce8b3129f2ad5.png)
垂直方向(height、margin):
height默认值为auto,但是区别于水平方向的auto,这里的auto是指内容区域高度,即内容区域多高,height多高
.outer {
height: 100px;
width: 100px;
background-color: blueviolet;
}
.inner {
width: 50px;
background-color: rgb(51, 11, 88);
color: #fff;
}
<div class="outer">
<div class="inner">文本内容</div>
</div>
![](https://i-blog.csdnimg.cn/blog_migrate/a0ac484dfbc8c3539862c749953a9f58.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5525fdaf10f4225c53bbfcbd5593812a.png)
如上,在未定义高度情况下,高度自动为内容区域高度37.333。
而垂直方向margin的auto就都是0了。
浮动
浮动的设计初衷是实现文字环绕效果,后来也被应用到了更多场景如横向排列。
正常元素默认是走文档流这一路线,通过float属性可以将元素改为浮动。
值 | 描述 |
left | 元素向左浮动。 |
right | 元素向右浮动。 |
none | 默认值。元素不浮动,并会显示在其在文本中出现的位置。 |
inherit | 规定应该从父元素继承 float 属性的值。 |
浮动元素特点:
1-当元素浮动后,元素的display属性会被改为为block,也就是变成了块级元素
![](https://i-blog.csdnimg.cn/blog_migrate/c97807b1a466dfd2146349c048a90ea6.png)
span {
float: left;
height: 100px;
background-color: bisque;
}
<span>span浮动</span>
如上,给span标签设置浮动后,它的高度可以设置了,正常情况,行内元素无法设置高度。
2-浮动元素也有包含块,其决定了浮动元素的活动范围。
3-width、height、margin的auto值
width与height的auto值,都为适应内容的宽度或高度。
![](https://i-blog.csdnimg.cn/blog_migrate/a94da8a551c9c3f58053ee73b13765d7.png)
div {
background-color: antiquewhite;
float: left;
}
<div>浮动</div>
![](https://i-blog.csdnimg.cn/blog_migrate/16fcc470761026667436ef588288b292.png)
如图,默认下width与height都为auto,它们的长度取决于内容的长度。
margin的auto值为0。
4-左浮动的元素向左上方排列,右浮动的元素向右上方排列
![](https://i-blog.csdnimg.cn/blog_migrate/b8c571e8dbed452904b2ccd9535bdac5.png)
.left {
background-color: antiquewhite;
float: left;
}
.right {
background-color: antiquewhite;
float: right;
}
<div class="left">左浮动</div>
<div class="right">右浮动</div>
5-当文档流块级元素在浮动元素前,浮动元素会给文档流块级元素让道。
![](https://i-blog.csdnimg.cn/blog_migrate/b7b9b5c5528f355d57ed47d93607fec6.png)
.left {
background-color: antiquewhite;
float: left;
}
.right {
background-color: antiquewhite;
float: right;
}
.normal {
background-color: blueviolet;
}
<div class="normal">文档流</div>
<div class="left">左浮动</div>
<div class="right">右浮动</div>
6-当文档流块级元素在浮动元素后,浮动元素会浮在文档流块级元素上,就不让道了。
![](https://i-blog.csdnimg.cn/blog_migrate/54b44e0ac35cf373eaf525fab87e01ae.png)
.left {
background-color: antiquewhite;
float: left;
}
.right {
background-color: antiquewhite;
float: right;
}
.normal {
background-color: blueviolet;
}
<div class="left">左浮动</div>
<div class="right">右浮动</div>
<div class="normal">文档流</div>
5、6可以记忆为对”浮动元素“而言,谁在前谁就是老大,谁就可以不让道。浮动元素不让道的标准就是”浮“在上面(仅相对于文档流块级元素)。
带背景色,看着不直观,所以去掉浮动元素的背景色
![](https://i-blog.csdnimg.cn/blog_migrate/f270acffbca873de778d6c9bfb274d0c.png)
至于文字“文档流”为何没有被左浮动元素压着,第7条会说。
看下面的例子
![](https://i-blog.csdnimg.cn/blog_migrate/91cfb0e3aab6faa52ae72047412239fa.png)
.left {
background-color: antiquewhite;
float: left;
}
.right {
background-color: antiquewhite;
float: right;
}
.normal {
background-color: blueviolet;
}
<div class="left">左浮动</div>
<div class="normal">文档流</div>
<div class="right">右浮动</div>
左浮动在前,可以不让道了,就浮在上面了。右浮动在后,得让道,就排到下面了。
7-文档流行内元素在排列时,会给浮动元素让道(这次跟顺序无关了)。
![](https://i-blog.csdnimg.cn/blog_migrate/98578c0afa6af0178bd88e9a41791785.png)
.left {
background-color: antiquewhite;
float: left;
}
.normal {
background-color: blueviolet;
}
<div class="left">左浮动</div>
<span class="normal">文档流</span>
<div class="left">左浮动</div>
带背景色看着不明显,所以去掉背景色
![](https://i-blog.csdnimg.cn/blog_migrate/74448459a6bc8e980ccca26b8a23995c.png)
文字环绕图片原理:
![](https://i-blog.csdnimg.cn/blog_migrate/60b0e75ab39f4f8ab983809e0d51f6bf.png)
.img {
width: 80px;
height: 100px;
float: left;
margin-right: 10px;
}
<img class="img" src="./uae.jpg">
<p>许嵩,1986年5月14日出生于安徽省合肥市,毕业于安徽医科大学,中国内地男歌手、音乐人、海蝶音乐公司(现为太合音乐集团)音乐总监。2009年1月发行首张词曲全创作专辑《自定义》。2010年1月发行第二张词曲全创作专辑《寻雾启示》。2011年4月发行第三张词曲全创作专辑《苏格拉没有底》。2012年7月发行第四张词曲全创作专辑《梦游计》。2014年8月发行第五张词曲全创作专辑《不如吃茶去》。2016... >>></p>
p标签是块级元素,但是文字部分,不会被浮动元素所覆盖,这是因为如果文字不是在行内元素内,浏览器会自动在文字外包裹一层行内元素。结合第7条—‘行内元素在排列时,会给浮动元素让道’,就可以理解为什么块级元素内的文字不会被浮动元素覆盖了,这个由浏览器自动生成的行内元素,不可见,叫做匿名行内框。
8-高度坍塌
![](https://i-blog.csdnimg.cn/blog_migrate/7d283583a7151f60743151c94df45627.png)
.outer {
padding: 5px;
background-color: brown;
}
.inner {
width: 15vw;
height: 15vw;
background-color: antiquewhite;
float: left;
margin-right: 10px;
margin-top: 1px;
}
<div class="outer">
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
</div>
如果不给inner加浮动,结果会是如下:
![](https://i-blog.csdnimg.cn/blog_migrate/c381ce7b94150d5c5f0aaa4d5fadd9f4.png)
以上由浮动属性造成的现象叫做高度坍塌(前者),文档流元素的默认高度是由内容区域决定的,在计算时,不会包含浮动元素(浮动元素脱离了文档流)。
解决方案:
通过使用clear属性,其包含以下值
值 | 描述 |
left | 左侧不允许浮动元素 |
right | 右侧不允许浮动元素 |
none | 允许两侧都有浮动元素。默认值 |
both | 左侧或右侧均不允许浮动元素 |
inherit | 元素继承其父级的 clear 值 |
设置了clear属性的标签会给浮动元素让道,也就是排列在了浮动元素下方。
![](https://i-blog.csdnimg.cn/blog_migrate/468a371e7e311a5ed8b3d4f810041211.png)
清除浮动方法一
.outer {
padding: 5px;
background-color: brown;
}
.inner {
width: 15vw;
height: 15vw;
background-color: antiquewhite;
float: left;
margin-right: 10px;
margin-top: 1px;
}
.clearfix {
clear: both;
}
<div class="outer">
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
<div class="clearfix"></div>
</div>
清除浮动方法二(推荐)
.outer {
padding: 5px;
background-color: brown;
}
.inner {
width: 15vw;
height: 15vw;
background-color: antiquewhite;
float: left;
margin-right: 10px;
margin-top: 1px;
}
.clearfix::after {
content: '';
display: block;
clear: both;
}
<div class="outer clearfix">
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
</div>
方法一通过在最后的位置添加一个标签,设置clear: both属性,解决了父元素高度坍塌问题,原理就是设置了clearfix css属性的标签会给浮动的所有元素让道,排列在它们的下方,而父盒子虽然不包含浮动元素,但是包含了设置了clearfix css属性的标签元素,而父盒子如果想要去包含它,就必须撑开自己,去包含设置了clearfix css属性的标签元素。因此,父盒子有了高度,其高度包括设置了clearfix css属性的标签元素及它上面的所有浮动元素(both情况下)。
方法二的原理与方法一本质相同,只是通过伪元素实现,这种方法既不用多写一个标签,也可以将clearfix属性复用到其它有高度坍塌问题的标签上,是推荐写法。
定位
用来指定一个元素在网页上的位置,通过position实现
值 | 描述 |
static | 默认值,即没有定位,遵循正常的文档流对象 |
fixed | 固定位置,元素的位置相对于浏览器窗口 |
relative | 相对定位,相对其正常位置 |
absolute | 绝对定位,相对于最近的已定位父元素,如果元素没有已定位的父元素,那么它的位置相对于<html>: |
sticky | 粘性定位,基于用户的滚动位置来定位 |
定位元素特点:脱离文档流(相对定位除外)
相对定位
不会使元素脱离文档流,只是相对其正常位置进行偏移,可以通过left、right、top、bottom四个属性设置偏移方向。
![](https://i-blog.csdnimg.cn/blog_migrate/9071ada354145b40e044102462437828.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6cba7121c4aa5514733999645b824cf5.png)
.box {
width: 50px;
height: 50px;
background-color: brown;
border: 1px solid #fff;
}
.relative {
position: relative;
left: 50px;
}
<div class="box"></div>
<div class="box relative"></div>
下面的元素使用相对定位,向左偏移了50px
绝对定位
绝对定位的元素是相对于其包含块的。从内向外找,其祖先元素中第一个定位元素(position不为static)就是其包含块
![](https://i-blog.csdnimg.cn/blog_migrate/6adb6e0dbc54b74ee7489e3ce674d649.png)
.grandfather {
position: relative;
background-color: brown;
width: 100px;
height: 100px;
}
.father {
background-color: rgb(238, 135, 135);
width: 50px;
height: 50px;
}
.son {
position: absolute;
bottom: 0;
background-color: rgb(255, 231, 231);
width: 25px;
height: 25px;
}
<div class="grandfather">
<div class="father">
<div class="son"></div>
</div>
</div>
儿子元素使用了绝对定位,那么其包含块就不再是父亲元素了,而是从内向外第一个使用定位元素的祖先元素,即祖父元素。
如果从内向外都没有定位元素,则绝对定位元素的包含块就是整个html标签(去掉grandfather的position属性结果如下)
![](https://i-blog.csdnimg.cn/blog_migrate/92f6839b2b8d6884565fc131368e3fab.png)
固定定位
固定定位的元素是相对于其包含块的。其包含块是视口,即浏览器的可视窗口部分(视口和整个html标签不同,使用固定定位的元素,无论怎样滚动浏览器,该元素位置都不会发生任何变化)
![](https://i-blog.csdnimg.cn/blog_migrate/b3b0f34efc5a731375a80c44ee35a9c3.png)
.button {
width: 30px;
height: 30px;
background-color: brown;
position: fixed;
bottom: 10px;
right: 10px;
}
<div class="button"></div>
无论如何滚动浏览器,按钮元素始终位于浏览器可视区域右下方。
粘性定位
相当于relative和fixed定位的混合,在正常情况下表现为relative,而达到了某种条件,就会由relative转为fixed。必须结合left、right、top、bottom一起使用,这四个属性就是某种条件。
![](https://i-blog.csdnimg.cn/blog_migrate/790c5a28f4a5b77fdad657ae91c7951f.gif)
* {
margin: 0;
padding: 0;
}
dl {
width: 100px;
border: 1px solid #000;
}
dt {
width: 100px;
color: #fff;
position: sticky;
top: 0;
}
dd {
border-bottom: 1px solid #000;
}
<dl>
<dt style="background-color: rgb(236, 101, 4);">块级元素</dt>
<dd>p</dd>
<dd>div</dd>
<dd>h1-h6</dd>
<dd>ul</dd>
<dd>ol</dd>
<dd>li</dd>
<dd>...</dd>
</dl>
<dl>
<dt style="background-color: rgb(154, 71, 12);">行内元素</dt>
<dd>a</dd>
<dd>span</dd>
<dd>b</dd>
<dd>strong</dd>
<dd>em</dd>
<dd>...</dd>
</dl>
<dl>
<dt style="background-color: rgb(4, 236, 139);">行内块元素</dt>
<dd>img</dd>
<dd>input</dd>
<dd>...</dd>
</dl>
<div style="height:500px"></div>
在正常情况下,dt标签就是relative定位,当达到临界值时(top:0),dt标签会变成fixed定位。临界值可通过left、right、top、bottom设置,且必须设置,否则,就没有粘性效果了。
这里面的临界值是指粘性定位元素与它从内向外的第一个设置了overflow属性的元素的相对距离,如果都没有,就是视口。如上例,dt元素外无任何设置了overflow属性的元素,所以,是相对于视口,当dt元素的top相对于视口的距离为0时,转为fixed定位。而当父元素从视口中消失,fixed定位结束,转为relative定位。
需要注意:当父元素设置了overflow属性(除默认值visible外),粘性定位会失效。原因:用上述例子举例,给dl添加了overflow:hidden,dt就相对于dl了,dl和dt的相对位置怎样都不会有变化。不可能达到临界值,故不会有粘性效果。