CSS笔记1:两栏布局和三栏布局

面经手写常考经典布局

  • 两栏布局:左定宽,右自适应
  • 三栏布局:左右定宽,中间自适应
    • 双飞翼布局: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
2
3
4
5
.clearfix:after{
content:"";
display:block;
clear:both;
}
  • 父级添加双伪元素
1
2
3
4
5
6
7
8
9
10
.clearfix:before, .clearfix:after{
content:"",
display:table;
}
.clearfix:after{
clear:both;
}
.clearfix{
*zoom:1
}

两栏布局

左边定宽,右边自适应

html

父元素包裹两个子元素,下面添加一个元素检验影响

1
2
3
4
5
<div class="container">
<div class="left">left</div>
<div class="right">right</div>
</div>
<div>其他,检测影响</div>

css

设置父元素宽度撑满,子元素背景色和高度

1
2
3
4
5
6
7
8
9
10
11
.container{
width: 100%;
}
.left{
height: 300px;
background-color: aqua;
}
.right{
height: 200px;
background-color: bisque;
}

float

左定宽浮动,右、父清除浮动

1
2
3
4
5
6
7
8
9
10
11
12
13
.container::after {
content: "";
display: block;
clear: both;
}
.left{
float: left;
width: 200px;
}
.right{
overflow: hidden;
/* margin-left: 200px */
}

理解:

左元素浮动,定宽(width: 200px)

右元素需要隔离浮动元素

image-20220419164416349

  • 可以设置bfc(overflow: hidden)
  • 也可以设置margin-left为左边元素的宽度(margin-left: 200px)

父元素清除浮动

image-20220419165029813

  • BFC(overflow: hidden)
  • clearfix(::after伪元素)

position

父相对,左定宽,右绝对

1
2
3
4
5
6
7
8
9
10
11
12
13
.container{
position: relative;

}
.left{
width: 200px;
}
.right{
position: absolute;
top: 0;
left: 200px;
right: 0;
}

理解

父元素:position: relative

  • 因为absolute定位的基准是祖先元素中第一个非static元素,这里需要为右元素提供基准

右元素:position: absolute

  • left: 200px,左偏移为左元素的宽度
  • top: 0,上偏移0,和左元素对齐
  • right: 0,右偏移0,自适应撑满

问题

子元素绝对定位,父元素相对定位时,也会产生高度塌陷,这个没办法解决,详见

flex

1
2
3
4
5
6
7
8
9
10
.container{
display: flex;
flex-direction: row;
}
.left{
width: 200px;
}
.right{
flex: 1;
}

三栏布局

顺序不定

左右定宽,中间自适应

html

左中右的定义顺序和布局方式有关

1
2
3
4
5
6
<div class="container">
<div class="left">left</div>
<div class="right">right</div>
<div class="middle">middle</div>
</div>
<div>check</div>

css

定义高度和颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.container{
width: 100%;
}
.left{
height: 100px;
background-color: bisque;
}
.middle{
height: 200px;
background-color: aquamarine;
}
.right{
height: 300px;
background-color: darkseagreen;
}

float

html的顺序:中在最后,因为元素只会收到之前的浮动元素影响

左右浮动定宽,中间设置margin为左右宽度,父清除浮动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.container::after{
content: "";
display: block;
clear: both;
}
.left{
float: left;
width: 100px;
}
.right{
float: right;
width: 100px;
}
.middle{
margin-left: 100px;
margin-right: 100px;
}

position

html的顺序:随意

父相对,左右绝对定宽,中间设置左右margin为左右宽度

依然存在高度塌陷问题,没办法,非要做只能在js中获取DOM元素高度赋给父元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.container{
position: relative;
}
.left{
position: absolute;
left: 0;
top: 0;
width: 100px;
}
.right{
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.middle{
margin-left: 100px;
margin-right: 100px;
}

flex

html需要改下顺序:左中右

1
2
3
4
5
6
<div class="container">
<div class="left">left</div>
<div class="middle">middle</div>
<div class="right">right</div>
</div>
<div>check</div>
1
2
3
4
5
6
7
8
9
10
11
12
.container{
display: flex;
}
.left{
width: 100px;
}
.middle{
flex: 1;
}
.right{
width: 100px;
}

中间元素最先渲染

两侧内容宽度固定,中间内容宽度自适应,中间一栏最先加载,也就是html结构锁定如下:

1
2
3
4
5
6
<div class="container">
<div class="middle">middle</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
<div>check</div>

float

参考:

圣杯和双飞翼布局都是通过 float + margin-left 实现,区别在于中间区域两边留白的处理

首先看共通的部分

  • 中间元素宽度100%,达到自适应撑满一行的效果
  • 左右元素定宽,这里假设都是100px
  • 三个元素都浮动 float: left
    • 因为是float,所以所有元素都在同一行,而中间元素撑满,所以效果上就是中间占一行,左右在下一行
    • image-20220419205116379
    • 将margin-left设为负值可以让元素左移,因为所有元素在同一行,所以左移后会移到到上一行
      • 左元素:margin-left: -100**%**,就是移动一个父容器宽度
      • image-20220419205607814
      • 右元素:margin-left: -100px,就是移动一个它自己的宽度
      • image-20220419205641904

以上实现可以得到一个撑满整个页面的中间元素,和两个吸附在左右的元素

但是还没有达到需求,我们需要设置中间元素左右两边留白,不然会被左右元素遮挡

不同点,留白

  • 双飞翼:中间元素额外添加子节点
    • 在中间元素的新增节点设置左右margin为两边留白
  • 圣杯:为左右元素额外设置relative相对定位
    • 在父元素中设置padding为两边留白
    • 左右元素需要额外设置relative偏移到正确位置

双飞翼

中间元素添加一个子节点,在新增节点设置左右margin为两边留白,要加载的内容也放在这个子节点里

html修改为:

1
2
3
4
5
6
7
<div class="container">
<div class="middle">
<div class="inner">middle</div>
</div>
<div class="left">left</div>
<div class="right">right</div>
</div>

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
*{
margin: 0;
padding: 0;
}
.container{
/* 清除浮动 */
overflow: hidden;
border: 1px solid black;
}
.container > div{
/* 全部设置float, relative */
float: left;
min-height: 20px;
}
.middle{
/* 宽度自适应撑满 */
width: 100%;
}
.inner{
background-color: aquamarine;
/* 设置margin */
margin: 0 100px;
}
.left{
background-color: bisque;
width: 100px;
/* 上移一行 */
margin-left: -100%;

}
.right{
background-color: darkcyan;
width: 100px;
/* 上移一行 */
margin-left: -100px;
}

圣杯

不像双飞翼额外在中间元素里加了子元素,圣杯保持原来的三个节点

思路是在父元素设置padding留白,子元素额外设置position进行偏移

position和float的兼容性

元素同时应用了position: relative、float、(top / left / bottom / right)属性后

则元素先浮动到相应的位置,然后再根据(top / left / bottom / right)所设置的距离来发生偏移

添加padding后,不加margin-left的效果

image-20220419210317552

加上margin-left的效果

image-20220419210548963

由于padding,left需要左移,right需要右移,那么加上position: relative就可以,加上的效果

image-20220419211056835

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
*{
margin: 0;
padding: 0;
}
.container{
/* 清除浮动 */
overflow: hidden;
/* 两边留白 */
padding: 0 100px;
border: 1px solid black;
}
.container > div{
/* 全部设置float, relative */
float: left;
min-height: 20px;
}
.middle{
background-color: aquamarine;
/* 宽度自适应撑满 */
width: 100%;
}
.left{
background-color: bisque;
width: 100px;
/* 上移一行 */
margin-left: -100%;
/* 左移 */
position: relative;
left: -100px;
}
.right{
background-color: darkcyan;
width: 100px;
/* 上移一行 */
margin-left: -100px;
/* 右移 */
position: relative;
right: -100px;
}

flex

flex也可以,但是要优先加载中间节点需要改一下顺序

  • html中的顺序:中左右

  • 页面中期望的顺序:左中右

  • 那么把左提前即可

    • flex子元素的属性:order,可以设为任意数值,越小排越左
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
*{
margin: 0;
padding: 0;
}
.container{
display: flex;
border: 1px solid black;
}
.container > div{
min-height: 20px;
}
.middle{
background-color: aquamarine;
flex: 1;
}
.left{
background-color: bisque;
width: 100px;
order: -1;
}
.right{
background-color: darkcyan;
width: 100px;
}
------ 本文结束 ❤ 感谢你的阅读 ------
------ 版权信息 ------

本文标题:CSS笔记1:两栏布局和三栏布局

文章作者:Lury

发布时间:2022年04月19日 - 21:10

最后更新:2022年04月19日 - 21:44

原始链接:https://luryzhu.github.io/2022/04/19/CSS/css1_columns/

许可协议:署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。