面经手写常考经典布局
- 两栏布局:左定宽,右自适应
- 三栏布局:左右定宽,中间自适应
- 双飞翼布局:float + margin-left + margin
- 圣杯布局:float + margin-left + padding + position
一般来说flex是最优解决方案
预备知识
BFC
Block Formatting Context,块级格式化上下文
是什么
- 文档流分为普通流,定位流(position),浮动流(float)相互间会有影响。
- BFC就是一个被隔离的区间(内部子元素不会对外面的元素产生影响)
触发条件
- body(BFC元素)
- float: left|right (非none)
- overflow: hidden | scroll | auto (非visible)
- display: inline-block | table-cell |table-caption | flex | grid (非block非none)
- position: absolute | fiexed (非relative)
浮动
float属性用于创建浮动框,将其移动到一边,直到左边缘或右边缘触及包含块或另一个浮动框的边缘。
浮动特性
- 脱离标准流的控制(脱标),移动到指定位置。
- 浮动的盒子不再保留原先的位置。
- 如果多个盒子都设置了浮动,则他们会按照属性值一行内显示并且顶端对齐排列。浮动的元素是互相贴靠在一起 的(没有缝隙),如果父级宽度装不下这些浮动的盒子,多出的盒子会另起一行对齐。
- 任何元素都能添加浮动特性,浮动元素会具有行内块元素特性。行内元素给了float属性后可以直接指定宽高。
- 一个元素是浮动的通常兄弟元素也应该浮动:浮动的盒子只会影响浮动盒子后面的标准流,不会影响前面的标准流。
清除浮动的方式
额外标签法(隔墙法):在浮动元素后添加一个空标签
- 新增元素必须是块级元素,如:
</br>
,<div style="clear:both"></div>
- 新增元素必须是块级元素,如:
将父级元素声明为BFC,例如:
overflow: hidden|auto|scroll
父级添加
:after
伪元素clear
指定一个元素是否必须移动(清除浮动后)到在它之前的浮动元素下面clear: left
表示移到前面float: left
的元素的下面,right
同理,both
表示移到所有左浮动和右浮动元素的下面
:after
伪元素,作为已选中元素的最后一个子元素必,- 必须要有content,不然伪元素效果不存在
- CSS3新标准中伪元素用双冒号
::after
,但仍然支持CSS2的单冒号写法,IE8只支持单冒号
1 | .clearfix:after{ |
- 父级添加双伪元素
1 | .clearfix:before, .clearfix:after{ |
两栏布局
左边定宽,右边自适应
html
父元素包裹两个子元素,下面添加一个元素检验影响
1 | <div class="container"> |
css
设置父元素宽度撑满,子元素背景色和高度
1 | .container{ |
float
左定宽浮动,右、父清除浮动
1 | .container::after { |
理解:
左元素浮动,定宽(width: 200px)
右元素需要隔离浮动元素
- 可以设置bfc(overflow: hidden)
- 也可以设置margin-left为左边元素的宽度(margin-left: 200px)
父元素清除浮动
- BFC(overflow: hidden)
- clearfix(::after伪元素)
position
父相对,左定宽,右绝对
1 | .container{ |
理解:
父元素:position: relative
- 因为absolute定位的基准是祖先元素中第一个非static元素,这里需要为右元素提供基准
右元素:position: absolute
- left: 200px,左偏移为左元素的宽度
- top: 0,上偏移0,和左元素对齐
- right: 0,右偏移0,自适应撑满
问题:
子元素绝对定位,父元素相对定位时,也会产生高度塌陷,这个没办法解决,详见
flex
1 | .container{ |
三栏布局
顺序不定
左右定宽,中间自适应
html
左中右的定义顺序和布局方式有关
1 | <div class="container"> |
css
定义高度和颜色
1 | .container{ |
float
html的顺序:中在最后,因为元素只会收到之前的浮动元素影响
左右浮动定宽,中间设置margin为左右宽度,父清除浮动
1 | .container::after{ |
position
html的顺序:随意
父相对,左右绝对定宽,中间设置左右margin为左右宽度
依然存在高度塌陷问题,没办法,非要做只能在js中获取DOM元素高度赋给父元素
1 | .container{ |
flex
html需要改下顺序:左中右
1 | <div class="container"> |
1 | .container{ |
中间元素最先渲染
两侧内容宽度固定,中间内容宽度自适应,中间一栏最先加载,也就是html结构锁定如下:
1 | <div class="container"> |
float
参考:
圣杯和双飞翼布局都是通过 float + margin-left 实现,区别在于中间区域两边留白的处理
首先看共通的部分:
- 中间元素宽度100%,达到自适应撑满一行的效果
- 左右元素定宽,这里假设都是100px
- 三个元素都浮动 float: left
- 因为是float,所以所有元素都在同一行,而中间元素撑满,所以效果上就是中间占一行,左右在下一行
- 将margin-left设为负值可以让元素左移,因为所有元素在同一行,所以左移后会移到到上一行
- 左元素:margin-left: -100**%**,就是移动一个父容器宽度
- 右元素:margin-left: -100px,就是移动一个它自己的宽度
以上实现可以得到一个撑满整个页面的中间元素,和两个吸附在左右的元素
但是还没有达到需求,我们需要设置中间元素左右两边留白,不然会被左右元素遮挡
不同点,留白:
- 双飞翼:中间元素额外添加子节点
- 在中间元素的新增节点设置左右margin为两边留白
- 圣杯:为左右元素额外设置relative相对定位
- 在父元素中设置padding为两边留白
- 左右元素需要额外设置relative偏移到正确位置
双飞翼
中间元素添加一个子节点,在新增节点设置左右margin为两边留白,要加载的内容也放在这个子节点里
html修改为:
1 | <div class="container"> |
css
1 | *{ |
圣杯
不像双飞翼额外在中间元素里加了子元素,圣杯保持原来的三个节点
思路是在父元素设置padding留白,子元素额外设置position进行偏移
position和float的兼容性:
元素同时应用了position: relative、float、(top / left / bottom / right)属性后
则元素先浮动到相应的位置,然后再根据(top / left / bottom / right)所设置的距离来发生偏移
添加padding后,不加margin-left的效果
加上margin-left的效果
由于padding,left需要左移,right需要右移,那么加上position: relative就可以,加上的效果
1 | *{ |
flex
flex也可以,但是要优先加载中间节点需要改一下顺序
html中的顺序:中左右
页面中期望的顺序:左中右
那么把左提前即可
- flex子元素的属性:order,可以设为任意数值,越小排越左
1 | *{ |