1 盒模型
:::info
盒模型是指HTML元素的内容计算宽高的方式,比较常用的有标准盒模型(W3C标准)和IE盒模型
:::
标准盒模型:width = content宽度
IE盒模型:width = content宽度+padding+border
在CSS属性中可以用box-sizing来控制,默认值为content-box,表示标准盒模型
如果需要切换成IE盒模型,可以使用border-box属性
box-sizing: border-box / content-box(默认值);
现在项目中基本使用的是border-box属性,避免content的宽度为100%后,padding与border的宽度会把屏幕撑开
2 外边距合并
:::info
外边距合并是指同一个BFC内相邻的元素或者空的元素的垂直方向的外边距重叠后会发生合并
:::
发生的条件
垂直方向,相邻元素(兄弟元素,父子元素)或者空元素,margin重叠,同一个BFC区域中,以上条件必须全部满足
重叠后外边距计算方式
- 同为正值或者负值:取绝对值最大的外边距为当前重叠元素间的外边距
- 一个为正一个为负值:两个外边距相加后得到的结果即为重叠元素的外边距
解决方法:
- 将其中元素设置为BFC区域,元素在不同的BFC区域中即可
父子元素或空元素:可以通过给父元素添加border或padding等内容使两个元素的margin被隔开
3 BFC
:::info BFC是块格式化上下文,是CSS在渲染过程中生成的一个块状区域(容器),它是浮动元素与在文档流元素的交互区域,规定了这个区域内的Block-Level Box如何布局,并且不会影响区域外的元素的布局 ::: 注意该区域的行内元素布局不会受到BFC特性的影响
BFC的特性与创建
BFC的特性:
同一个BFC的垂直方向元素外边距重叠时会发生合并
- BFC不会与浮动元素重叠
- BFC在计算高度时会计算子元素中浮动元素的高度,所以不会出现父元素高度塌陷问题
- BFC内部布局不会影响外部元素的布局
常见的出现BFC的场景:
- html根元素是一个BFC
- 浮动元素,float不为none
- position为absolute或fixed
- overflow不为visible
- display为inline-block、table、inline-table、table-cell、table-row的元素
- display为flow-root的元素
display为flex、inline-flex、grid、inline-grid元素的直接子元素
display: flow-root
由于创建BFC的属性都有其真正的含义,故在创建BFC的时候会有一些副作用,比如
float: left; /* 造成元素浮动 */overflow:hiddent; /* 截断溢出内容 */
display: flow-root创建了一个无副作用的BFC
BFC的应用场景
主要是利用BFC的一些特性来解决问题
HTML结构如下:<div class='bfcPage'><div class='box1'>box1</div><div class='box2'>box2</div></div>
解决外边距合并问题
在box1或者box2的样式中添加创建BFC的属性,比如overflow: hidden或者display: flow-root,使box1与box2不在同一个BFC中
.bfcPage {display: flow-root;}.box1 {margin-bottom: 20px;width: 50px;height: 50px;background-color: aquamarine;}.box2 {margin-top: 30px;background-color: #eee;overflow: hidden;}
- 进行布局或解决父元素高度坍塌问题
box1是浮动元素,box2是BFC
.bfcPage {display: flow-root;}.box1 {float: left;width: 50px;height: 50px;background-color: aquamarine;}.box2 {margin-left: 20px;background-color: #eee;overflow: hidden;}
效果如下:
bfcPage的高度为50px,高度被浮动元素撑开
BFC内元素不会与浮动元素重叠,所以box1与box2并排展示,并没有被覆盖,可以进行两列自适应布局
tipsbox1是浮动元素,脱离文档流,box2的margin-left是相当于bfcPage的左边框而言,由于box1的宽度为50,而box2的左边距为20,所以box1与box2之间没有间距
4 水平垂直居中
水平垂直居中有多种方法,position+transfrom,flex等,可以分为2种情况讨论
子元素定宽高
HTML结构如下,A定宽高
<div className="mainpage"><div className="test size">A</div></div>
则CSS样式使用position: absolute 和margin-left在已知宽高的情况下移动
.mainpage {position: relative;width: 300px;height:300px;background-color: aqua;}.size{width: 60px;height:60px;background-color: crimson;}.test {position: absolute;left: 50%;top: 50%;margin-left: -30px;margin-top: -30px;}
除了使用margin-left/top的方式将元素移到中间位置外,还可以使用transform
.test {position: absolute;left: 50%;top: 50%;transform: translate(-30px, -30px);}
还可以使用margin:auto
.test {position: absolute;left:0;right:0;top:0;bottom:0;margin:auto;}
使用calc进行计算属性,但比较消耗性能
.test {position: absolute;left:calc(50% - 30px);top:calc(50% - 30px);}
子元素不定宽高
HTML结构如下
<div className="mainpage"><div className="test">A</div></div>
使用flex,只用设置容器就可以实现,子元素不需要进行设置
.mainpage{display: flex;justify-content: center;align-items: center;width: 300px;height:300px;background-color: aqua;}
使用line-height + vertical-align,需要将子元素改成行内元素生效
.mainpage {width: 300px;height:300px;line-height:300px; /* 行内元素垂直居中,会被继承 */text-align: center; /* 行内元素水平居中,会被继承 */font-size: 0px; /* 消除空白节点 */background-color: aqua;}.test {vertical-align: middle;line-height: normal; /* line-height会被继承,所以需要重新设置 */display: inline-block; /* 设置成行内元素text-align才会生效 */font-size: 14px; /* font-size也会继承 */background-color: crimson;}
vertical-align只对行内元素生效,vertical-align: middle可以让元素近似于垂直居中(涉及到基线问题)
也可以使用绝对定位和transform
.mainpage {width: 300px;height:300px;position:relative;background-color: aqua;}.test {position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);}
还可以使用table-cell,不需要设置子元素的样式,但是如果有多个子元素,子元素是垂直排列的
.mainpage {width: 300px;height:300px;display: table-cell;vertical-align:middle;background-color: aqua;}
如果需要多个子元素并行排列,需要设置子元素
.mainpage {width: 300px;height:300px;display: table-cell;vertical-align: middle;background-color: aqua;}.test {display: inline-block;}
5 两列布局
一列定宽,一列自适应
以左列定宽,右列自适应为例:HTML结构如下
<div className="mainpage"><div className="testa">A</div><div className="testb">B</div></div>
可以通过flex来实现
.mainpage {width: 100%;height:100%;display: flex;background-color: aqua;}.testa {width: 300px;flex-grow:0;flex-shrink: 0;background-color:chocolate;}.testb {flex-grow: 1;flex-shrink: 1;background-color:violet;}
float实现,需要清除浮动
.mainpage {width: 100%;height:100%;background-color: aqua;}.testa {float: left;width: 300px;height:100%;background-color:chocolate;}.testb {height:100%;margin-left: 300px;background-color:violet;}
绝对定位实现
.mainpage {width: 100%;height:100%;position: relative;background-color: aqua;}.testa {width: 300px;height:100%;position: absolute;top: 0;left: 0;background-color:chocolate;}.testb {position: absolute;top: 0;left: 300px;right: 0;height:100%;background-color:violet;}
一列不定宽,一列自适应
使用flex实现
.mainpage {width: 100%;height:100%;display: flex;background-color: aqua;}.testa {flex-grow:0;flex-shrink: 0;background-color:chocolate;}.testb {flex-grow: 1;flex-shrink: 1;background-color:violet;}
也可以使用BFC
tips这个也可以用在一列定宽,一列自适应的场景
.mainpage {width: 100%;height:100%;background-color: aqua;}.testa {float: left;height:100%;background-color:chocolate;}.testb {height:100%;display: flow-root;background-color:violet;}
6 三列布局
HTML结构如下
<div className="mainpage"><div className="testa">A</div><div className="testb">B</div><div className="testc">C</div></div>
两边定宽,中间自适应
万能的flex,flex对布局简直好用
.mainpage {width: 100%;height:100%;display: flex;background-color: aqua;}.testa, .testc {width: 100px;flex-grow:0;flex-shrink: 0;background-color:chocolate;}.testb {flex-grow: 1;flex-shrink: 1;background-color:violet;}
使用float,中间的元素一定要float,脱离文档流,否则会把最右边的元素挤到下一行
.mainpage {width: 100%;height:100%;box-sizing: border-box;padding: 0 100px;background-color: aqua;}.testa{width: 100px;height:100%;float: left;margin-left: -100px;background-color:chocolate;}.testc{width: 100px;height:100%;float: right;margin-right: -100px;background-color:chocolate;}.testb {float: left; // 一定要float,脱离文档流,否则会把C挤到下一行width: 100%;height:100%;background-color:violet;}
两列靠左,一列靠右,垂直居中
使用flex和margin-left,flex的子元素使用margin auto时会有意想不到的效果
.mainpage {width: 100%;height:100%;display: flex;justify-content: flex-start;align-items: center;background-color: aqua;}.testa {width: 100px;height: 30px;background-color:chocolate;}.testb {width: 100px;height: 50px;background-color:violet;}.testc {width: 100px;height: 80px;margin-left: auto;background-color:chocolate;}
7 flex 布局
HTML结构如下
<div className="mainpage"><div className="testa">A</div><div className="testa">A</div><div className="testa">A</div><div className="testa">A</div></div>
一行3列居中,最后不足三列的靠左
可以对最后一项使用margin-right:auto,但是需要判断最后一项是不是3的倍数
对flex布局的子元素使用margin,可以实现任意行的左右对齐,而不会影响其他行
.mainpage{display: flex;flex-wrap: wrap;align-items: center;justify-content: space-around;width: 300px;height:300px;background-color: aqua;}.testa {height: 50px;width: 90px;background-color: chocolate;&:last-child {margin-right: auto;}&:nth-child(3n){margin-right: 0;}}
正方形div,且随父元素的宽高变化,长宽比例固定
可以使用&:after来实现div正方形,原因在于margin/padding设置百分百时都是以父元素的width来进行计算的,伪元素设置padding和margin时根据容器的宽度来计算的
.mainpage{width: 100%;background-color: aquamarine;}.testa {display: inline-block;width:20%;background-color: cadetblue;&:nth-child(2n) {background-color: coral;}&:before {content: '';display: inline-block;padding-bottom: 100%;width: 0.1px;vertical-align: middle; /* 2个inline-block会上下错位,原因是基线变了,可以设置vertical-align来改变基线 */}}
也可以使用vw,将宽度设置为vw
1vw与1vh表示视口宽度和高度的的1%,假设4个子元素并排显示,且为正方形宽高自适应,可以将元素的高度设置为25vw,就可以实现宽高自适应了
