CSS-009-BFC

BFC

Block Formatting Context

块格式化上下文

CSS规范中对 BFC 的描述

9.4.1 块格式化上下文

浮动,绝对定位元素,非块盒的块容器(例如,inline-blocks,table-cells和table-captions)和’overflow’不为’visible’的块盒会为它们的内容建立一个新的块格式化上下文

在一个块格式化上下文中,盒在竖直方向一个接一个地放置,从包含块的顶部开始。两个兄弟盒之间的竖直距离由’margin’属性决定。同一个块格式化上下文中的相邻块级盒之间的竖直margin会合并

在一个块格式化上下文中,每个盒的left外边(left outer edge)挨着包含块的left边(对于从右向左的格式化,right边挨着)。即使存在浮动(尽管一个盒的行盒可能会因为浮动收缩),这也成立。除非该盒建立了一个新的块格式化上下文(这种情况下,该盒自身可能会因为浮动变窄)

MDN 对 BFC 的描述

一个块格式化上下文(block formatting context) 是Web页面的可视化CSS渲染出的一部分。它是块级盒布局出现的区域,也是浮动层元素进行交互的区域。

一个块格式化上下文由以下之一创建:

  • 根元素或其它包含它的元素
  • 浮动元素 (元素的 float 不是 none)
  • 绝对定位元素 (元素具有 position 为 absolute 或 fixed)
  • 内联块 (元素具有 display: inline-block)
  • 表格单元格 (元素具有 display: table-cell,HTML表格单元格默认属性)
  • 表格标题 (元素具有 display: table-caption, HTML表格标题默认属性)
  • 具有overflow 且值不是 visible 的块元素,
  • display: flow-root 触发BFC
  • column-span: all 应当总是会创建一个新的格式化上下文,即便具有 column-span: all 的元素并不被包裹在一个多列容器中。

一个块格式化上下文包括创建它的元素内部所有内容,除了被包含于创建新的块级格式化上下文的后代元素内的元素。

块格式化上下文对于定位 (参见 float) 与清除浮动 (参见 clear) 很重要。定位和清除浮动的样式规则只适用于处于同一块格式化上下文内的元素。浮动不会影响其它块格式化上下文中元素的布局,并且清除浮动只能清除同一块格式化上下文中在它前面的元素的浮动。

张鑫旭对 BFC 的描述

http://www.zhangxinxu.com/wordpress/2015/02/css-deep-understand-flow-bfc-column-two-auto-layout/

BFC全称”Block Formatting Context”, 中文为“块级格式化上下文”。啪啦啪啦特性什么的,一言难尽,大家可以自行去查找,我这里不详述,免得乱了主次,总之,记住这么一句话:BFC元素特性表现原则就是,内部子元素再怎么翻江倒海,翻云覆雨都不会影响外部的元素。所以,避免margin穿透啊,清除浮动什么的也好理解了。

BFC 到底是什么?

先思考一个问题:

请问:什么是色情?

联邦最高法院大法官斯图尔特更有一句名言

我不知道什么是色情,不过,我看了之后,就能知道

I know it when I see it

类似地:

1、我不知道什么是 BFC
2、但是你写出样式,我就知道这是不是 BFC

BFC 就是这样的东西(堆叠上下文也是)

1、它没有定义
2、它只有特性/功能

功能1:爸爸管儿子

用 BFC 包住浮动元素。(这不是清除浮动,.clearfix 才是清除浮动)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html>
<head>
<style>
.baba{
border: 10px solid red;
min-height: 10px;
display: flow-root; /*触发BFC*/
}
.erzi{
background: green;
float:left; /* 浮动就会脱离文档流 ,导致 baba 的高度塌陷 */
width: 300px;
height: 100px;
}
</style>
</head>
<body>
<div class="baba">
<div class="erzi"></div>
</div>
</body>
</html>

如何触发BFC

  • 父级 浮动、定位、或者 display = inline-block\table-cell\table-caption 或者 display不是block的值的容器、 overflow 不为 visible的
    • overflow:auto
    • overflow:hidden 会引发副作用,如果内部元素,超出内容不会显示
    • display:inline-block
    • display:table-cell
    • display:flow-root 让当前元素触发BFC,CSS3新出的属性,兼容性不太好

解释BFC内部元素 margin融合问题

  • 如果两个div没有浮动,它们在一个div中,它们的竖直margin会合并
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
<style>
.baba{
border: 10px solid red;
min-height: 10px;
display: flow-root; /*触发BFC*/
}
.erzi{
background: green;
width: 400px;
height: 100px;
margin:10px;
}
</style>
</head>
<body>
<div class="baba">
<div class="erzi"></div>
<div class="erzi"></div>
</div>
</body>
</html>

一个BFC包含它的元素内的所有内容,如果它的孩子元素是BFC,那么这个孩子的后代元素是不会被包含进来的

通俗理解

  • baba是BFC
  • erzi是 baba的子元素,同时也是BFC
  • sunzi 是 erzi的子元素,它的内容就不会被 baba包含
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
<!DOCTYPE html>
<html>
<head>
<style>
.baba{
border: 10px solid red;
width:500px;
min-height: 10px;
display:flow-root;
}
.erzi{
background: green;
width: 400px;
height: 100px;
margin:10px;
float:left; /* 触发BFC */
margin-top:100px; /* 由于父级 触发BFC所以 这个距离会被包含进 baba里*/
}
.sunzi{
height: 50px;
width: 400px;
margin-top:200px; /* 由于 sunzi被 BFC元素 erzi罩着, 所以无法被包含进 baba内 */
background:blue;
/* 由于 erzi在带sunzi,所以baba 就不管这个sunzi了 */
}
</style>
</head>
<body>
<div class="baba">
<div class="erzi">
<div class="sunzi"></div>
</div>
</div>
</body>
</html>

功能2:兄弟之间划清界限

用 float + 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
26
27
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<style>
.gege{
width: 100px;
min-height: 600px;
border: 3px solid red;
float: left;
margin-right: 20px;
}

.didi{
min-height: 600px;
border: 5px solid green;
overflow:auto;
/* display:flow-root; */
}
</style>
</head>
<body>
<div class="gege">gege</div>
<div class="didi">1234</div>
</body>
</html>
  • 第一个方式就是 overflow:auto
  • 第二个方式就是 display:flow-root;

如何回答面试官

千万别解释什么是 BFC,一解释就错
用上面的例子回答什么是 BFC

常见问题

BFC和文档流有什么关系

  • BFC说的是一个div有一些属性后(float:left 或position:absolute)它自己就是BFC。BFC说的是这个 div 的特性,说的是这个div会包住它里面,它里面的内容是不会变得
  • 文档流是 内联元素从左到右,块级元素从上到下排列
  • BFC影响一个元素的宽高,文档流影响是排列顺序

BFC使用场景

  • 爸爸管儿子(参考上面的功能1),注意这不是清除浮动,这是BFC让爸爸管儿子
    • BFC可以模拟清除浮动的效果,但是我可以直接 clearfix,那么BFC就没意义了,BFC会导致副作用 如 overflow:hidden;的时候,但是clearfix不会有副作用,除非所有浏览器都支持display:flow-root
    • 不要用BFC清除浮动
  • 兄弟之间划清界限(参考上面的功能2)
    • 也就是以前的左右布局
    • 同样也可以不用它,用flex解决这些问题
    • BFC是时代的产物

margin穿透

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
<head>
<style>
.baba{
background:red;
}
.erzi{
height: 100px;
margin-top:100px;
background:green;
}
</style>
</head>
<body>
<div class="baba">
<div class="erzi"></div>
</div>
</body>
</html>
  • 现在 erzi 的 margin会穿过 baba
  • 给 baba 添加 overflow:hidden 就能触发BFC,不让 erzi穿出来,但是有副作用就是 erzi内如果有定位元素超出容易会被隐藏
  • 所以 你只能给 baba 加 display:flow-root 或者 borer

什么情况下一定要BFC呢?

没有任何情况一定要BFC,所有的场景都可以不用BFC实现

面试一定要搞懂BFC

CSS-008-布局套路

布局套路

左右布局

float + clearfix

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style>
.parent{
border:1px solid red;
}
.child{
height: 30px;
float:left;
}

.child:nth-child(1){
width:30%;
background:blue;
}

.child:nth-child(2){
width:70%;
background:red
}

.clearfix::after{
content:'';
display:block;
clear:both;
}

</style>
</head>
<body>
<div class="parent clearfix">
<div class="child"></div>
<div class="child"></div>
</div>
</body>
</html>

实战PC页面的套路

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
<!DOCTYPE html>
<html>
<head>
<style>
*{margin:0;padding:0;box-sizing:border-box;}
.main-center{margin:0 auto;}
.parent{
border:1px solid red;
margin:0 auto;
background:#ddd;
min-width:600px;
}
.child{
float:left;
}

.child:nth-child(1){
width:100px;
background:#333;
color:white;
text-align:center;
height:36px;
line-height:36px;
}

.child:nth-child(2){
float:right;
}

.content{
border:1px solid black;
margin-right:10px;
}

.nav{
line-height:24px;
padding:6px 0;
}

.navItem{
float:left;
margin-left:20px;
}

.clearfix::after{
content:'';
display:block;
clear:both;
}
.clearfix{
zoom:1; /* 兼容IE6 */
}

.banner{
width: 800px;
height: 300px;
background:#888;
margin-top: 10px;
margin-left:auto;
margin-right:auto;
}

.pictures{
width: 800px;
margin:0 auto;
background:green;
}

.pictures .xxx{
margin-left:-4px;
margin-right:-4px;
}
.picture{
height: 194px;
width: 194px;
float:left;
margin:4px;
background:#ddd
}

.pictures2{
width: 800px;
margin:0 auto;
background:green;
display:flex;
flex-wrap:wrap;
justify-content:space-between;
}

.picture2{
height: 194px;
width: 194px;
margin-top:4px;
margin-bottom:4px;
background:#ddd
}

.pictures3{
width: 800px;
margin:0 auto;
background:green;
}

.pictures3 .xxx{
display:flex;
flex-wrap:wrap;
margin:0 -4px;
}

.picture3{
height: 194px;
width: 194px;
margin:4px;
background:#ddd;
border:1px solid red;
}

.pictures4{
width: 800px;
margin:0 auto;
background:green;
}

.pictures4 .xxx{
display:flex;
flex-wrap:wrap;
margin:0 -4px;
}

.picture4{
height: 194px;
width: calc(25% - 8px);
margin:4px;
background:#ddd;
border:1px solid red;
}

.art{
background:#ddd;
height: 300px;
width: 800px;
margin:0 auto;
}

.art .sider{
float:left;
width: calc(33.333333% - 20px);
margin-right:20px;
}

.art .sider .child-ad{
height: 300px;
border:1px solid black;
}

.art .main{
float:left;
height: 300px;
border:1px solid black;
width:66.66666%;
}
</style>
</head>
<body>
<div class="parent clearfix">
<div class="child">logo</div>
<div class="child">
<div class="nav clearfix">
<div class="navItem">导航1</div>
<div class="navItem">导航2</div>
<div class="navItem">导航3</div>
<div class="navItem">导航4</div>
<div class="navItem">导航5</div>
</div>
</div>
</div>

<div class="banner"></div>

<h3 style="margin:0 auto;width:800px;">float+margin负边距 样品展示区</h3>
<div class="pictures">
<div class="xxx clearfix">
<div class="picture"></div>
<div class="picture"></div>
<div class="picture"></div>
<div class="picture"></div>
<div class="picture"></div>
<div class="picture"></div>
<div class="picture"></div>
<div class="picture"></div>
</div>
</div>

<h3 style="margin:0 auto;width:800px;">flex 样品展示区</h3>
<p style="margin:0 auto;width:800px;">隐藏了bug 如果是7个 第二行就会很难看</p>
<div class="pictures2">
<div class="picture2"></div>
<div class="picture2"></div>
<div class="picture2"></div>
<div class="picture2"></div>
<div class="picture2"></div>
<div class="picture2"></div>
<div class="picture2"></div>
<div class="picture2"></div>
</div>

<h3 style="margin:0 auto;width:800px;">flex 样品展示区:修复bug</h3>
<div class="pictures3">
<div class="xxx">
<div class="picture3"></div>
<div class="picture3"></div>
<div class="picture3"></div>
<div class="picture3"></div>
<div class="picture3"></div>
<div class="picture3"></div>
<div class="picture3"></div>
</div>
</div>


<h3 style="margin:0 auto;width:800px;">flex 样品展示区:使用 calc</h3>
<div class="pictures4">
<div class="xxx">
<div class="picture4"></div>
<div class="picture4"></div>
<div class="picture4"></div>
<div class="picture4"></div>
<div class="picture4"></div>
<div class="picture4"></div>
<div class="picture4"></div>
<div class="picture4"></div>
</div>
</div>

<div class="art">
<div class="sider">
<div class="child-ad">广告1</div>
</div>
<div class="main">广告2</div>
</div>
</body>
</html>

手机端

  • 直接将上面的样式 媒体查询 + flex即可

CSS-007-grid布局

Grid 布局

先画一个网格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
<style>
.container{
display:grid;
/* 列方向: 左右 50px 中间自适应 */
grid-template-columns:50px auto 50px;
/* 行方向: 上下 50px 中间自适应 */
grid-template-rows:50px auto 50px;
height:100vh;
border:1px solid red;
}
</style>
</head>
<body>
<div class="container"></div>
</body>
</html>

gird布局实现 PC页面布局

  • 两栏布局
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
40
41
42
43
44
<!DOCTYPE html>
<html>
<head>
<style>
.container {
height: 100vh;
border:1px solid red;

display:grid;
grid-template-columns: 10% auto 10%;
grid-template-rows: 50px auto 50px;
grid-template-areas:
"header header header"
". main aside"
"footer footer footer";
background:pink;
}
.header {
grid-area: header;
background:#ddd;
}
.main {
grid-area: main;
background:red;
}
.aside {
grid-area: aside;
background:yellow;
}
.footer{
grid-area: footer;
background:blue;
}
</style>
</head>
<body>
<div class="container">
<div class="header">header</div>
<div class="main">main</div>
<div class="aside">aside</div>
<div class="footer">footer</div>
</div>
</body>
</html>

使用 grid-template 实现上面的需求

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
.container {
height: 100vh;
border:1px solid red;
background:pink;

display:grid;
/*
grid-template-columns: 10% auto 10%;
grid-template-rows: 50px auto 50px;
grid-template-areas:
"header header header"
". main aside"
"footer footer footer";
*/
grid-template:
/* 定义header 高度 */
"header header header" 50px
/* 定义 main aside 高度自适应 */
". main aside" auto
/* 定义 footer高度 */
"footer footer footer" 50px
/* 定义列的宽度比例 */
/ 10% auto 10%
;
}

横列之间的缝隙

1
2
3
/* 列缝隙的大小 */
grid-column-gap: 10px;
grid-row-gap: 15px;

grid代替上面的代码

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
40
41
42
43
44
45
<!DOCTYPE html>
<html>
<head>
<style>
.container {
height: 100vh;
border:1px solid red;

display:grid;
/* 定义行 在定义列*/
grid: 50px auto 50px / 10% auto 10%;
background:pink;
}
.header {
/* 跨三根线 */
grid-column: 1 / span 3;
grid-row:1;
background:#ddd;
}
.main {
grid-column: 2;
grid-row:2;
background:red;
}
.aside {
grid-column: 3;
grid-row:2;
background:yellow;
}
.footer{
grid-column: 1 / 4;
grid-row:3;
background:blue;
}
</style>
</head>
<body>
<div class="container">
<div class="header">header</div>
<div class="main">main</div>
<div class="aside">aside</div>
<div class="footer">footer</div>
</div>
</body>
</html>

参考

CSS-006-flex布局

flex

flex 出现之前如何布局

  • normal flow 正常流,文档流
  • float + clear
  • position relative + absolute
  • display:inline-block
  • margin 负值

flex基本概念

  • 水平方向叫做 main axis
    • 从左往右 main start -> main end
  • 垂直方向叫做 cross axis
    • 从上到下 cross start -> cross end

flex container 的属性

  • flex-direction 方向
    • row
    • row-reverse 水平方向反转
    • column 纵向排列
    • column-reverse 垂直方向反转
  • flex-wrap 换行
    • 子元素设置了宽度 200px但还是收缩的挤在一起, 父元素设置这个属性 flex-wrap:wrap 就会折行
  • flex-flow 上面两个的简写
  • justify-content 主轴方向对齐方式
    • space-between 两端对齐
    • space-around 拉手现象
    • flex-start
    • flex-end
    • center 缩在中间
  • align-items 侧轴对齐方式
    • stretch 把元素伸开,伸到最大元素的高度
    • flex-start 自身高度往上靠(收缩)
    • flex-end 自身高度往下靠(收缩)
    • baseline 文字基线对齐
    • center 垂直居中
  • align-content 多行/列内容对齐方式(用的少)

flex-item 属性

  • flex-grow 增长比例(空间过多时)
  • flex-shrink 收缩比例(空间不够时)
  • flex-basis 默认大小(一般不用)
  • flex 上面三个的缩写
    • flex: 1 2 100px; 增长的时候 1份,缩的时候 2份,原始占 100px
  • order 顺序(代替双飞翼)
  • align-self 自身的对齐方式
    • 比如 父元素设置了 align-items:flex-start 贴着顶部,你可以在某个子元素设置自己的对齐方式 align-self:center

实战

手机页面布局 (topbar + main + tabs)

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<style>
* {margin:0;padding:0;box-sizing:border-box;}
ul {list-style: none;}
/*header和footer的高度都是100px,为什么不一样高?*/
header {
background: #ddd;
border: 1px solid;
height: 100px;
}
footer ul{
background: #ddd;
display: flex;
height: 100px;
}
main {
overflow: auto;
}
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
footer ul>li {
height: 100%;
width:25%;
background: red;
}
</style>
</head>
<body>
<div class="container">
<header>
header
</header>
<main>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
<p>main</p>
</main>
<footer>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</footer>
</div>
</body>
</html>

产品列表 (ul>li*9)

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
<!DOCTYPE html>
<html>
<head>
<style>
*{margin:0;padding:0;border-box:box-sizing;}
ul{list-style:none;}
ul{
display:flex;
flex-wrap:wrap;
margin:auto;
border:1px solid black;
width: 350px;
justify-content:space-between;
}

li{
height: 100px;
width: 100px;
border:1px solid red;
margin:10px 0;
}


</style>
</head>
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
</html>

PC布局

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
<!DOCTYPE html>
<html>
<head>
<style>
*{margin:0;padding:0;border-box:box-sizing;}
.content{
display:flex;
}

.content>main{
height: 400px;
flex:1;
background:red;
}
.content>aside{
width:120px;
background:blue;
}
.content>nav{
width:100px;
background:green;
}

header{background:grey;height:100px;}
footer{background:grey;height:100px;}

</style>
</head>
<body>
<header></header>
<div class="content">
<aside></aside>
<main></main>
<nav></nav>
</div>
<footer></footer>
</body>
</html>

完美居中

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
<!DOCTYPE html>
<html>
<head>
<style>
*{margin:0;padding:0;border-box:box-sizing;}
.parent{
border:1px solid red;
height:400px;
display:flex;
justify-content:center;
align-items:center;
}
.child{
border:1px solid red;
}
</style>
</head>
<body>
<div class="parent">
<div class="child">
hahahaha
<br>
hhh
<br>
hhh
</div>
</div>
</body>
</html>

CSS-005-移动端响应式

媒体查询

Demo01:宽度800px以内 都为红色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<style>
@media (max-width:800px){
body{
background:red;
}
}
</style>
</head>
<body>
</body>
</html>

适配不同屏幕手机

  • min-width:xxx 大于等于 xxx 的时候生效
  • max-width:xxx 小于等于 xxx 的时候生效
  • 注意顺序 从大往下写,不然会被覆盖
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
40
41
<!DOCTYPE html>
<html>
<head>
<style>
/* 769 ~ 正无穷*/
@media (min-width:769px){
body{
background:black;
}
}
/* 0 ~ 768 */
@media (max-width:768px){
body{
background:green;
}
}
/* 0 ~ 425 */
@media (max-width:425px){
body{
background:yellow;
}
}

/* 0 ~ 375 */
@media (max-width:375px){
body{
background:orange;
}
}

/* 0 ~ 320 */
@media (max-width:320px){
body{
background:red;
}
}
</style>
</head>
<body>
</body>
</html>

媒体查询的另一种写法 “and”

1
2
3
4
5
6
7
8
9
10
11
12
13
/* 0 ~ 320 */
@media (max-width:320px){
body{
background:red;
}
}

/* 321 ~ 375 */
@media (min-width:321px) and (max-width:375px) {
body{
background:red;
}
}
1
2
3
<link rel="stylesheet" href="style.css" media="only screen and (max-width):320px">

无论如何 都会下载这个css,只不过他会在屏幕小于等于320的时候生效

meta viewport

为什么页面要缩放,因为一开始都是 900多像素宽,手机只有300像素宽,不缩放怎么看呢?

于是我不想缩放咋办呢?

  • 告诉浏览器别给我缩放
1
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

手机端的交互

  • 没有 hover
  • 有 touch 事件,别去监听 click
  • 没有 resize 事件
  • 没有滚动条

CSS-003-堆叠上下文

堆叠上下文

堆叠顺序

盒模型

一个盒子中主要的属性就5个:

  • width
  • height
  • padding
  • border
  • margin

一个 div 背景色到底在哪个层级?

1
2
3
4
5
6
7
8
div{
width:200px;
height:200px;
border:10px solid red;
padding:15px;
margin:15px;
background:black;
}
  • 给 border 设置半透明,你发现 black 在后面

结论

背景色在border的后面

div上有文字内容 谁先谁后?

答案是

1
背景色 >  border > 文字/内联元素

情况复杂了

  • parent 里的 child 有文字
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
.parent{
width:200px;
height:200px;
border:10px solid rgba(255,0,0,0.5);
padding:15px;
margin:15px;
background:green;
color:red;
}
.child{
background:pink;
margin-top:-15px;
color:black;
}
</style>
</head>
<body>
<div class="parent">
AAAA
<div class="child">BBB</div>
</div>
</body>
</html>

结论

1
2
3
4
- parent的文字 会盖住 child 的背景色
- child的文字 会盖住 parent的 文字,因为它是后出现的

background > border > child的 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
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html>
<head>
<style>
.parent{
width:200px;
height:200px;
border:10px solid rgba(255,0,0,0.5);
padding:15px;
margin:15px;
background:green;
color:red;
text-indent:-10px;
}
.child{
background:pink;
color:black;
height: 30px;
}
.float{
float:left;
background:blue;
height: 30px;
width: 30px;
}
</style>
</head>
<body>
<div class="parent">
AAAA
<div class="float"></div>
<div class="child"></div>
</div>
</body>
</html>
  • 浮动元素 盖住了 child 说明,浮动元素天生比块级元素要高
  • parent的文字 盖在 浮动元素上面

如果浮动元素里面有文字咋办?

  • 答案是 浮动元素 是 parent 的孩子节点, parent的文字 显示层级天生就比 浮动元素高
1
2
3
4
5
6
- parent的文字 会盖住 child 的背景色
- child的文字 会盖住 parent的 文字,因为它是后出现的
- 浮动元素 会盖住 child
- parent的文字 会盖住 浮动元素

background > border > child的 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html>
<head>
<style>
.parent{
width:200px;
height:200px;
border:10px solid rgba(255,0,0,0.5);
padding:15px;
margin:15px;
background:green;
color:red;
text-indent:-10px;
}
.child{
background:pink;
color:black;
height: 30px;
}
.float{
float:left;
background:blue;
height: 30px;
width: 30px;
margin-top:-10px;
}
.relative{
position:relative;
height: 50px;
width: 50px;
background:orange;
}
</style>
</head>
<body>
<div class="parent">
AAAA
<div class="relative"></div>
<div class="float"></div>
<div class="child"></div>
</div>
</body>
</html>
  • 定位元素会在 float 之前

z-index

1
2
3
parent 内 同级别元素直接加 z-index 不会影响 堆叠顺序

只有 position不为 static 默认值的元素 z-index才会生效

堆叠顺序

可以理解为堆叠作用域。跟 BFC 一样,我们只知道一些属性会触发堆叠上下文,但并不知道堆叠上下文是什么。

  • 根元素 (HTML),
  • z-index 值不为 “auto”的 绝对/相对定位 (只记住这个就行了,其他凭感觉)
  • 一个 z-index 值不为 “auto”的 flex 项目 (flex item),即:父元素 display: flex|inline-flex,
  • opacity 属性值小于 1 的元素(参考 the specification for opacity),
  • transform 属性值不为 “none”的元素,
  • mix-blend-mode 属性值不为 “normal”的元素,
  • filter值不为“none”的元素,
  • perspective值不为“none”的元素,
  • isolation 属性被设置为 “isolate”的元素,
  • position: fixed
  • 在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值(参考 这篇文章)
  • -webkit-overflow-scrolling 属性被设置 “touch”的元素

CSS-002-宽度与高度

宽度与高度

文档流

文字两边对其

多行文字两端对其

1
<p style="text-align:justify;"> fjalsfjdsalkj</p>

单行文字两端对齐

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
span{
width:5em;
display:inline-block;
border:1px solid red;
text-align:justify;
height: 20px;
line-height:20px;
overflow:hidden;
}
span::after{
content:'';
display:inline-block;
width:100%;
}
</style>
</head>
<body>
<div>
<span>姓名</span>
<br>
<span>手机号</span>
</div>
</body>
</html>

文字省略溢出

单行文本溢出省略号

1
2
3
white-space:nowrap;
overflow:hidden;
text-overflow:ellipse;

多行文本溢出

1
2
3
4
5
6
.block-with-text {
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}

文字水平垂直居中

水平

1
text-align:center;

文字垂直居中 ,比如要求40px

  • 不要写死宽度
1
2
3
line-height:24px;
padding:8px 0;
/* 一旦设置高度,多行文本就有bug */

margin 合并

  • 给 parent 设置 border 上下的 margin 就不会合并
  • 给 parent 设置 padding 上下的 margin 就不会合并
  • 给 parent 设置 overflow:hidden 上下的 margin 就不会合并
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
body{
border:1px solid green;
}
.parent{
margin:10px;
outline:1px solid red;
}
.child{
border:10px solid black;
background:pink;
height: 100px;
margin:10px;
}
</style>
</head>
<body>
<div class="parent">
<div class="child"></div>
</div>
</body>
</html>

总结

视口内容水平垂直居中

child 定宽定高

1
2
3
4
5
6
7
8
9
10
11
12
13
.child{
top:0;
left:0;
right:0;
bottom:0;
position:absolute;
width:100px;
height:100px;
margin:auto;
}
.parent{
height:100vh;
}

child 不定宽不定高

  • flex
1
2
3
4
5
6
7
8
9
.child{
height:auto;
}
.parent{
height:100vh;
display:flex;
justify-contnet:center;
align-items:center;
}

实现 1比1的div

  • 高度为0
  • 宽度自适应
1
2
3
4
5
.one{
border:1px solid red;
padding-top:100%;
/* padding 和 宽度一样 */
}

CSS-001-CSS不正交

CSS不正交

CSS难学

Margin塌陷问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
.demo{
border:1px solid red;
height: 60px;
margin:10px;
}
</style>
</head>
<body>
<div class="demo"></div>
<div class="demo"></div>
<div style="border-top:0.1px solid green;"></div>
<div class="demo"></div>
<div style="display:table;"></div>
<div class="demo"></div>
</body>
</html>
  • 第一个和第二个div之间的margin 不是 20px 而是 10px

如何不让他塌陷?

  • 加入一个 div 设置 border-top:0.1px solid green;
  • 加入一个 div 设置 display:table;
  • 加入一个 div 设置 display:flex;

这就是CSS不正交之处

Margin贯穿

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
.parent{
outline:1px solid red;
}
.child{
outline:1px solid green;
height: 60px;
margin-top:100px;
background:green;
}
</style>
</head>
<body>
<div class="parent">
<div class="child"></div>
</div>
</body>
</html>
  • child 的 margin 贯穿了 parent 把div整体 顶了下来

如何让他不贯穿

  • 给 parent 加 border border-top:0.1px solid blue;
  • 给 parent 设置 overflow:hidden;
  • 给 parent 设置 display:flex; ,但要同时设置 child width:100%;,因为是 flex

display 影响 li 标签小圆点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
li{
display:inline;
/* display:block; */
}
</style>
</head>
<body>
<li>1</li>
<li>2</li>
<li>3</li>
</body>
</html>

li 默认是 display:list-item;

position 会改变 display

  • child display 已经从 inline 变成了 block
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
.parent{
background:pink;
height: 100px;
position:relative;
}
.child{
display:inline;
position:absolute;
right:0;
bottom:0;
background:green;
}
</style>
</head>
<body>
<div class="parent">
<div class="child">hahaha</div>
</div>
</body>
</html>

position:fixed 和 transform相互影响

  • 直觉上 fixed 会相对视口定位到左下角
  • 而因为 parent 里 设置了 transform:scale(1.1); 因为要做动画所以会把 parent内的所有东西一起包含进来,于是 child就从 视口左下角 定位到了 parent 左下角
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
.parent{
background:pink;
height: 300px;
transform:scale(1.1);
}
.child{
display:inline;
position:fixed;
left:0;
bottom:0;
background:green;
}
</style>
</head>
<body>
<div class="parent">
<div class="child">hahaha</div>
</div>
</body>
</html>

float 对 inline 元素影响

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
.parent{
background:pink;
height: 200px;
}
.float{
background:green;
float:left;
width:100px;
opacity:0.5;
}
.child{
height: 100px;
background:white;
width:200px;
}
</style>
</head>
<body>
<div class="parent">
<div class="float">aaa</div>
<div class="child">hahaha</div>
</div>
</body>
</html>
  • float 不影响 child的位置
  • float 能感知 到 child 里的文字形成 图文混排

CSS容易学

布局常规套路

两栏、三栏布局

  • PC
    • IE8 只能控制宽度设置 float 了
    • Chrome flex
  • Mobile
    • flex

居中

水平居中

1
2
3
<div class="parent">
<div class="child"></div>
</div>
  • child 宽度不确定, margin-left:20px;margin-right:20px;
  • child 宽度确定 margin-left:auto;margin-right:auto;

如果是 inline元素 直接text-align:center

垂直居中

  • child高度确定不确定都是这样
    • parent 上加 上下内边距 padding-top:20px;padding-bottom:20px;

难点在于 parent 高度确定如何做?

  • 理论上不该出现这个现象,应该避免这种现象。
  • 实在避免不了也有办法
    • IE: table
    • chrome:flex
    • mobild: flex

Node-web03_03Next

Next深入2

SSR

SSG 存在问题

跟用户数据相关的时候,我们必须获取用户数据后,在渲染页面,这样就无法静态化

  • 虽然也能把用户内容静态化,但是新浪微薄,几亿个用户,难道生产那么多html?
  • 数据更新快,用户自己改身份信息 年龄,昵称等

咋办?

  • BSR 客户端渲染,下拉更新
  • SSR 服务端渲染,下拉更新
  • 但是不能用 getStaticProps
    • 因为这个是 SSG
    • 它是 yarn build 后
  • 可用 getServerSideProps(context:NextPageContext)

获取用户浏览器信息

  • 不同浏览器user-agent不同

  • 定义 getServerSideProps 函数

  • pages/posts/index_ssr.tsx
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
import { GetServerSideProps, NextPage } from 'next';
import React from 'react';
type Props = {
browser: string;
}
const Index_SSR: NextPage<Props> = (props) => {
return (
<>
<div>SSR服务端生成
你的浏览器是:{props.browser}
</div>
</>
)
}

export default Index_SSR;

export const getServerSideProps: GetServerSideProps = async (context) => {
const ua = context.req.headers['user-agent'];
return {
props: {
browser: ua
}
}
}

getServerSideProps

  • 运行时机
    • 无论开发还是生产环境
    • 都是在请求后运行 getServerSideProps
  • 回顾 getStaticProps
    • 开发环境,每次请求后运行
    • 生产环境,build时运行一次
  • 参数
    • context 类型为 NextPageContext
    • context.req / context.res 可以获取请求和响应
    • 一般只用 context.req

SSR缺点

  • 无法获取客户端信息,如浏览器窗口大小

三种渲染方式如何选择

1
2
3
4
5
6
7
8
9
10
11
if(有动态内容吗?){
if(跟客户端相关?){
// 跟请求用户数据相关
return BSR || SSR
}else{
// 跟用户数据无关
return SSG
}
}else{
return 直接html
}

升级SSG:文章详情

  • step01 修改跳转链接

    • pages/posts/index_ssg.tsx
      1
      <Link href={`/posts/${p.id}`}>{p.id}</Link>
  • step02 新建 pages/posts/[id].tsx

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
40
import { getPost, getPostIds, Post } from "lib/posts";
import { NextPage } from "next";

type Props = {
post: Post
}
const postShow: NextPage<Props> = (props) => {
const { post } = props
return (
<div>
文章详情
<h1>{post.title}</h1>
<article>
{post.content}
</article>

</div>
)
}

export default postShow;

export const getStaticPaths = async () => {
const idList = await getPostIds();
console.log(idList)
return {
paths: idList.map(id => ({ params: { id: id } })),
fallback: false
}
}

export const getStaticProps = async (x: any) => {
const id = x.params.id;
const post = await getPost(id);
return {
props: {
post: JSON.parse(JSON.stringify(post))
}
}
}

pages/posts/[id].tsx的作用

  • 声明路由 /posts/:id
  • 同时是 /posts/:id的页面实现程序

你需要实现三个东西

  • PostsShow组件 从props里接受 post数据
  • 实现 getStaticProps,从第一个参数接受 params.id
  • 实现 getStaticPaths,返回 id列表

fallback的作用

是否自动兜底