CSS布局方式

CSS布局方法包括定位布局、浮动布局、弹性布局,通过这些布局方式,可以玩出各种不同的花样。

定位布局

定位布局通过position属性来实现。

position: static

static是默认值,是静态定位,就是元素出现在正常的元素流中。

position: relative

relative是相对定位。在一个相对定位的元素上设置top,left,bottom,right属性会让它偏移其正常位置(如果不设置,则保持原位置不变)。但是其他元素不会受它的影响(即其他元素不会去弥补相对定位的元素偏移后的空隙位置)。

position: absolute

absolute是绝对定位,它会相对于最近的“positioned”祖先元素定位(即position值不是static的元素)。如果没有“positioned”元素,那么它会相对于body来定位。

position: fixed

fixed是固定定位。固定定位的元素会相对于视窗来定位,意味着即使页面滚动,它还是会停留在相同的位置。

固定定位的元素会脱离文档流,也就是它原有的位置不会被保留。

position: sticky

粘性定位。最开始会像relative那样对原来的位置进行偏移,一旦超过一定的阈值之后,就会作为fixed定位,对于视窗进行定位。


浮动布局

浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边缘位置。

image-20180910230338781

如果包含框太窄,无法容纳水平排列的三个浮动元素,那么其他浮动块向下移动,直到有足够的空间。如果浮动元素的高度不同,那么它们向下移动时可能会被其他浮动元素“卡住”。

image-20180910230500209

float布局最开始是为了实现文字环绕而设计的。

image-20180910213712444

但浮动元素并不仅仅实现这一的效果。浮动元素会在浮动层上面进行排布,原先文档流中的元素位置会被删除。但是浮动元素的浮动层部分会把补上来的元素的文字挤出去。

image-20180910213901541

这是因为设置浮动的元素会形成BFC,并且元素的宽度不再适应父元素宽度,而是适应自身内容宽度。

清除浮动

clear属性规定元素的哪一边不可以有浮动元素。

  • none: 两边都可以有浮动元素
  • left:左边不可以有浮动元素
  • right:右边不可以有浮动元素
  • both:两边都不可以有浮动元素
  • inherit:继承父元素的clear属性

clear属性通常是和另一个被设置为浮动的元素搭配使用的。比如元素A设置了float:left,那个设置clear:left能让元素B不会和元素A发生重合,而是出现在元素A的下方,但元素A的浮动位置不会发生改变。


弹性布局

弹性布局能为盒模型提供很大的灵活性。定义了flex的容器是一个可伸缩容器,容器本身会根据容器中的元素动态设置资深大小,当容器被设置一个大小时,将会自动调整容器中的元素适应新大小。

Setup

所有的容器都可以指定为flex布局:

1
2
3
.box {
display: flex;
}

行内元素也可以使用flex布局:

1
2
3
.box {
display: inline-flex;
}

webkit内核的浏览器要加上-webkit前缀

1
2
3
4
.box {
display: -webkit-flex; /* Safari */
display: flex;
}

设为Flex布局后,子元素的float,clearvertical-align属性均失效。

基本概念

设置为Flex的元素叫做Flex容器(flex container)。它的子元素被称为Flex项目(flex item)。

容器默认存在两条轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴开始的位置叫做main start,结束位置叫做main end,交叉轴的开始位置叫做cross start,结束位置叫做cross end

单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size

img

容器属性

  • flex-direction 决定主轴的方向(即项目排列方向)

    1
    2
    3
    .box {
    flex-direction: row | row-reverse | column | column-reverse;
    }

    image-20180911224252905

  • flex-wrap 如果一行排不下,如何换行

    1
    2
    3
    .box {
    flex-wrap: nowrap | wrap | wrap-reverse; /* 不转行 | 转行,第一行在上 | 转行,第一行在下 */
    }
  • flex-flow flex-directionflex-wrap的缩写,默认是row nowrap

  • justify-content 项目在主轴上的对齐方式

    1
    2
    3
    .box {
    justify-content: flex-start | flex-end | center | space-between | space-around;
    }

    img

  • align-items 项目在交叉轴上如何对齐

    1
    2
    3
    .box {
    align-items: flex-start | flex-end | center | baseline | stretch;
    }

    img

  • align-content 多根轴线的对齐方式

    1
    2
    3
    .box {
    align-content: flex-start | flex-end | center | space-between | space-around | stretch;
    }

    img

项目属性

  • order 项目的排列顺序,数值越小,排列越靠前

  • flex-grow 项目的放大比例(默认为0,按比例分配剩余空间)

  • flex-shrink 项目的缩小比例,默认为1

  • flex-basis 分配多余空间之前,项目占据的主轴空间

  • align-self 运行单个项目有与其他项目不一样的对齐方式

    1
    2
    3
    .item {
    align-self: auto | flex-start | flex-end | center | baseline | stretch;
    }

    img


常见布局技巧

水平居中

行内元素
  • text-align: center

  • 块级元素可以转换成行内元素,再text-align: center

    1
    2
    3
    <div class="wrapper">
    <div class="test"></div>
    </div>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    text-align: center;
    }
    .test {
    width: 50px;
    height: 50px;
    background: red;
    display: inline-block | inline-flex; //div转换成内联块级元素
    }

    image-20180912142228021

块级元素
  • margin: auto

    块级元素左右外边距auto可以实现水平居中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    }
    .test {
    width: 50px;
    height: 50px;
    background: red;
    margin: 0 auto;
    }
  • margin计算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    }
    .test {
    width: 50px;
    height: 50px;
    background: red;
    position: relative;
    margin-left: calc(50% - 25px);
    }
  • 弹性布局

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    display: flex;
    justify-content: center;
    }
    .test {
    width: 50px;
    height: 50px;
    background: red;
    }
  • 绝对定位+ margin: auto

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    position: relative;
    }
    .test {
    width: 50px;
    height: 50px;
    background: red;
    position: absolute;
    left: 0;
    right: 0;
    margin: auto;
    }

垂直居中

行内元素
  • line-height设置为父容器的高度(适用于一行文字的情况)
块级元素

以下方法均达到下图效果:

1
2
3
<div class="wrapper">
<div class="test"></div>
</div>

image-20180912142752550

  • 直接使用margin计算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    }
    .test {
    width: 50px;
    height: 50px;
    margin-top: calc(50% - 25px);
    }
  • display:table-cell + vertical-align: middle

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    display: table-cell;
    vertical-align: middle;
    }
    .test {
    width: 50px;
    height: 50px;
    background: red;
    }
  • flex布局+align-items: center

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    display: flex;
    align-items: center;
    }
    .test {
    width: 50px;
    height: 50px;
    background: red;
    }
  • 相对定位

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    }
    .test {
    width: 50px;
    height: 50px;
    position: relative;
    top: 50%;
    margin-top: -25px;
    }
  • 绝对定位+负的margin

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    position: relative;
    }
    .test {
    width: 50px;
    height: 50px;
    position: absolute;
    top: 50%;
    margin-top: -25px;
    }
  • 绝对定位 + margin: auto

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    .wrapper {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    position: relative;
    }
    .test {
    width: 50px;
    height: 50px;
    background: red;
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto;
    }

两栏布局(一栏定宽,一栏自适应)

1
2
<div class="left">定宽</div>
<div class="right">自适应</div>

目标效果:

image-20180910214549271

1. 相对布局
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
* {
margin:0;
padding: 0;
}

.left {
width: 200px;
height: 400px;
background: red;

}
.right {
height: 400px;
background: yellow;
width: calc(100% - 200px);
position: relative;
left: 200px;
top: -400px;
}
2. 绝对布局
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
* {
margin:0;
padding: 0;
}

.left {
width: 200px;
height: 400px;
background: red;

}
.right {
height: 400px;
background: yellow;
width: calc(100% - 200px);
position: absolute;
left: 200px;
top: 0;
}
3. 浮动布局1-float + margin
1
2
3
4
5
6
7
8
9
10
11
.left {
width: 200px;
heigth: 300px;
float: left;
background-color: red;
}
.rigth {
margin: 200px;
height: 300px;
background-color: yellow;
}
4. 浮动布局: 两边都浮动
1
2
3
4
5
6
7
8
9
10
11
12
.left {
width: 200px;
height: 400px;
background: red;
float: left;
}
.right {
height: 400px;
background: yellow;
float: right;
width: calc(100% - 200px);
}

image-20180912150850318

5. 弹性布局 + flex: 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
body{ /* 应该加一层div包裹,避免其他元素布局受影响 */
display: flex;
}
.left {
width: 200px;
height: 400px;
background: red;

}
.right {
height: 400px;
background: yellow;
flex:1;
}

三栏布局(两边定宽,中间自适应)

1. 左右float, 中间margin
1
2
3
<div class="left">左栏</div>
<div class="right">右栏</div>
<div class="middle">中间栏</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.left {
width: 200px;
height: 300px;
background: red;
float: left;
}
.right {
width: 300px;
height: 300px;
background: green;
float: right;
}
.middle {
background: yellow;
margin-left: 210px;
margin-right: 310px;
}

image-20180910215538173

缺点:当浏览器宽度小于左右栏宽度之和时,右栏会被挤下去

image-20180910215638282

2. 左右position定位,中间margin
1
2
3
<div class="left">左栏</div>
<div class="right">右栏</div>
<div class="middle">中间栏</div>
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
* {
margin: 0;
padding: 0;
}
div {
height: 300px;
}
.left {
width: 200px;
background: red;
position: 0;
top: 0;
left: 0;
}
.right {
width: 300px;
background: green;
position: absolute;
top: 0;
right: 0;
}
.middle {
background: yellow;
margin: 0 320px 0 220px;
}

image-20180910220341784

缺点:当父元素有内外边距时,中间栏位置会产生偏差(所以加上了reset)

3. flex布局
1
2
3
4
5
<div id="wrapper">
<div class="left">左栏</div>
<div class="right">右栏</div>
<div class="middle">中间栏</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#wrapper {
display: flex;
height: 300px
}
.left {
width: 200px;
background: red;
}
.right {
width: 300px;
background: green;
}
.middle {
width: 100%; /* flex: 1 */
margin: 0 20px;
}

image-20180910221326693

缺点:会有兼容性问题

参考

学习CSS布局

Flex布局教程:语法篇