文章目录
  1. 1. 如何设置块级元素水平居中?
    1. 1.1. 方法一(差):设置width + margin
    2. 1.2. 方法二(可):设置max-width + margin
  2. 2. 盒子模型
    1. 2.1. 盒子模型的结构
    2. 2.2. 外边距折叠( Collapsing margins )
      1. 2.2.1. 折叠后 margin 的计算
      2. 2.2.2. 不发生margin折叠的情况
    3. 2.3. 浮动元素、inline-block 元素、绝对定位元素
      1. 2.3.1. 创建了块级格式化上下文的元素
      2. 2.3.2. 元素自身的margin折叠
    4. 2.4. 内容的尺寸与元素框的总尺寸
    5. 2.5. CSS3属性:box-sizing
  3. 3. position属性
    1. 3.1. position属性值
    2. 3.2. position例子-左固定宽度,右自适应宽度
  4. 4. float
    1. 4.1. 如何清除浮动?
    2. 4.2. float例子-左固定宽度,右自适应宽度
  5. 5. 百分比宽度
    1. 5.1. 百分比宽度布局-左固定百分比右自适应
  6. 6. 媒体查询
  7. 7. inline-block
    1. 7.1. inline-block 布局-左固定百分比右自适应
  8. 8. CSS3属性-column
  9. 9. flexbox
    1. 9.1. 使用 Flexbox 的简单布局
    2. 9.2. 使用 Flexbox 的牛逼布局
    3. 9.3. 使用 Flexbox 的居中布局

重在实践,把常用的布局及其实践总结在这备忘,方便以后查询和使用。
包含了 “如何设置块级元素水平居中” 、 “如何实现左固定宽度或百分比,右边自适应” 等常见问题。
和 “外边距折叠” 这类重要的概念。及各种常见的属性和布局。

PS:DEMO借助了jsfiddle而现在它需要翻墙才能访问,
因此DEMO的效果也需要翻墙才能访问 (-.-|||


如何设置块级元素水平居中?

方法一(差):设置width + margin

1
2
3
4
#main {
width: 600px;
margin: 0 auto;
}

DEMO:

方法二(可):设置max-width + margin

1
2
3
4
#main {
max-width: 600px;
margin: 0 auto;
}

DEMO:

盒子模型

盒子模型的结构

为了给文档树中的各个元素排版定位(布局),浏览器会根据渲染模型1为每个元素生成四个嵌套的矩形框, 分别称作 content box、padding box、border box 和 margin box,它们是不可分割的,并可能会重合, 这就是 CSS 规范中描述的“框模型”(box model)。它是以 CSS 的角度去看一个元素被渲染后的抽象形态。 是一个元素自身的构成部分,不同于布局:多个元素在页面上的定位。

盒模型

盒子3D模型:
盒模型
对于盒子模型如想理解详细,请看这里: CSS 框模型( Box module )

外边距折叠( Collapsing margins )

Collapsing margins,即外边距折叠,指的是毗邻的两个或多个外边距 (margin) 会合并成一个外边距。

其中所说的 margin 毗邻,可以归结为以下两点:

  • 这两个或多个外边距没有被非空内容、padding、border 或 clear 分隔开。
  • 这些 margin 都处于普通流中。(既 in-flow,非浮动元素,非定位元素)

其规则为: 两个或多个 毗邻 的普通流中的块元素 垂直 方向上的 margin 会折叠
了解详情,请看:CSS 框模型( Box module )

试一试其中的例子:
DEMO-1(毗邻):
HTML

1
2
3
4
5
6
7
<div class="lightpink">
<div class="lightgreen">
<div class="lightyellow">
<div class="lightblue">D BLOCK</div>
</div>
</div>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.lightpink{
background-color:lightpink;
border:1px solid red;
width:100px;
}
.lightgreen{
margin:50px 0;
background-color:lightgreen;
height:50px;
width:50px;
}
.lightyellow{
background-color:lightyellow;
margin:20px 0;
}
.lightblue{
background-color:lightblue;
margin:100px 0;
}

在没有被非空内容、padding、border 或 clear 分隔开(毗邻)的情况下,一个元素的 margin-top 会和它普通流中的第一个子元素(非浮动元素等)的 margin-top 相邻; 只有在一个元素的 height 是 “auto” 的情况下,它的 margin-bottom 才会和它普通流中的最后一个子元素(非浮动元素等)的 margin-bottom 相邻。

此例中的 lightgreen块(margin:50px 0;) 与 它的第一个且最后一个子元素 lightyellow块(margin:100px,0;) 毗邻 且 lightyellow块(margin:50px 0;) 与 它的第一个且最后一个元素 lightblue块(margin:100px 0;)毗邻,
他们的 margin-top 发生合并,取最大值,此时lightgreen块的 margin-top 为 100px。
而因为 lightgreen块(margin:50px 0;)有 height 值(height:50px;)因此它的 margin-bottom 与其最后一个子元素 lightyellow块(margin:20px 0;)的 margin-bottom 并不相邻,因此 margin-bottom 不发生合并,此时lightgreen块的 margin-bottom 为 50px。

所以我们看到了 lightpink块 被 lightgreen块 撑开 而margin-top和margin-bottom看起来不同,就是这个道理啦…


折叠后 margin 的计算

DEMO-2(参与折叠的 margin 都是正值):

1
2
<div style="height:50px; margin-bottom:50px; width:50px; background-color: red;">A</div>
<div style="height:50px; margin-top:100px; width:50px; background-color: green;">B</div>

由上结果观察到:A 与 B 间距 100px;
结论:在 margin 都是正数的情况下,取其中 margin 较大的值为最终 margin 值。


DEMO-3(参与折叠的 margin 都是负值):

1
2
<div style="height:100px; margin-bottom:-75px; width:100px; background-color: red;">A</div>
<div style="height:100px; margin-top:-50px; margin-left:50px; width:100px; background-color: green;">B</div>

由上结果观察到:A 与 B 重叠部分高度 75px;
结论:当 margin 都是负值的时候,取的是其中绝对值较大的,然后,从 0 位置,负向位移。


DEMO-4(参与折叠的 margin 中有正值,有负值):

1
2
<div style="height:50px; margin-bottom:-50px; width:50px; background-color: red;">A</div>
<div style="height:50px; margin-top:100px; width:50px; background-color: green;">B</div>

由上结果观察到:A 与 B 间距 50(px)=100+(-50);
结论:有正有负,先取出负 margin 中绝对值中最大的,然后,和正 margin 值中最大的 margin 相加。


DEMO-5(相邻的 margin 要一起参与计算,不得分步计算):
要注意,相邻的元素不一定非要是兄弟节点,父子节点也可以,即使不是兄弟父子节点也可以相邻。

而且,在计算时,相邻的 margin 要一起参与计算,不得分步计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div style="background-color:green; width:50px;">
before A
</div>
<div style="margin:50px 0; background-color:green; width:50px;">
<div style="margin:-60px 0;">
<div style="margin:150px 0;">A</div>
</div>
</div>
<div style="margin:-100px 0; background-color:green; width:50px;">
<div style="margin:-120px 0;">
<div style="margin:200px 0;">B</div>
</div>
</div>
<div style="background-color:green; width:50px;">
after B
</div>

为了方便观察结果我添加了一个 “before A” 和 “after B”
由上结果观察到:before A 与 A 间距 90px; A 与 B 间距 80px; B 与 after B 间距 80px;

错误的计算方式:算 A 和 B 之间的 margin,分别算 A 和其父元素的折叠,然后与其父元素的父元素的折叠,这个值算出来之后,应该是 90px。依此法算出 B 的为 80px;然后,A和B折叠,margin 为 90px。

请注意,多个 margin 相邻折叠成一个 margin,所以计算的时候,应该取所有相关的值一起计算,而不能分开分步来算。

以上例子中,A 和 B 之间的 margin 折叠产生的 margin,是6个相邻 margin 折叠的结果。将其 margin 值分为两组:

  • 正值:50px,150px,200px
  • 负值:-60px,-100px,-120px
    根据有正有负时的计算规则,正值的最大值为 200px,负值中绝对值最大的是 -120px,所以,最终折叠后的 margin 应该是 200 + (-120) = 80px。

不发生margin折叠的情况

浮动元素、inline-block 元素、绝对定位元素

浮动元素、inline-block 元素、绝对定位元素的 margin 不会和垂直方向上其他元素的 margin 折叠
浮动元素的 margin 在垂直方向上也不会发生 margin 折叠,即使和它相邻的子元素也不会。
DEMO-6(浮动元素margin不折叠):

1
2
3
4
<div style="margin-bottom:50px; width:50px; height:50px; background-color:green;">A</div>
<div style="margin-top:50px; width:100px; height:100px; background-color:green; float:left;">
<div style="margin-top:50px; background-color:gold;">B</div>
</div>

两个绿色的块儿之间,相距100px,显然B与A之间没有发生折叠,而若 B 和它的浮动包含块发生 margin 折叠的话,金色的条应该位于绿色块的最上方,显然,没有发生折叠。

创建了块级格式化上下文的元素

创建了块级格式化上下文的元素,不和它的子元素发生 margin 折叠
块级格式化上下文:http://www.w3.org/TR/CSS2/visuren.html#block-formatting
DEMO-7(以”overflow : hidden” 的元素为例):

1
2
3
<div style="margin-top:50px; width:100px; height:100px; background-color:green; overflow:hidden;">
<div style="margin-top:50px; background-color:gold;">B</div>
</div>

若 B 和它的 “overflow:hidden” 包含块发生 margin 折叠的话,金色的条应该位于绿色块的最上方,此例中显然没有折叠。

元素自身的margin折叠

元素自身的 margin-bottom 和 margin-top 相邻时也会折叠
自身 margin-bottom 和 margin-top 相邻,只能是自身内容为空,垂直方向上 border、padding 为 0。

DEMO-8(元素自身的 margin-bottom 和 margin-top折叠):

1
2
3
<div style="border:1px solid red; width:100px;">
<div style="margin-top: 100px;margin-bottom: 50px;"></div>
</div>

由上结果观察到:红框框里面的div的margin-bottom 和 margin-top折叠了,因为如果不折叠他的高会是150px,折叠之后它的高为100px。红色框框div的宽为100px,结果刚好是个正方形。


内容的尺寸与元素框的总尺寸

在 CSS 中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。

假设框的每个边上有 10 个像素的外边距和 5 个像素的内边距。如果希望这个元素框达到 100 个像素,就需要将内容的宽度设置为 70 像素,请看下图。
盒模型

1
2
3
4
5
#box {
width: 70px;
margin: 10px;
padding: 5px;
}

当你设置了元素的宽度,实际展现的元素却能够超出你的设置:因为元素的边框和内边距会撑开元素。
DEMO:

1
2
3
4
5
6
7
8
9
10
11
.simple {
width: 500px;
margin: 20px auto;
}
.fancy {
width: 500px;
margin: 20px auto;
padding: 50px;
border-width: 10px;
}

以前有一个代代相传的解决方案是数学。CSS开发者需要用比他们实际想要的宽度小一点的宽度,需要减去内边距和边框的宽度。值得庆幸地是你不需要再这么做了…

CSS3属性:box-sizing

当你设置一个元素为 box-sizing: border-box; 时,此元素的内边距和边框不再会增加它的宽度。这里有一个与上例相同的例子,唯一的区别是两个元素都设置了 box-sizing: border-box;
DEMO:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.simple {
width: 500px;
margin: 20px auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.fancy {
width: 500px;
margin: 20px auto;
padding: 50px;
border-width: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}

此时两个div不含margin的width都为500px,这就和我们设置的值一样了。

既然没有比这更好的方法,一些CSS开发者想要页面上所有的元素都有如此表现。所以开发者们把以下CSS代码放在他们页面上:

1
2
3
4
5
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}

这样可以确保所有的元素都会用这种更直观的方式排版。

既然 box-sizing 是个很新的属性,目前你还应该像我之前在例子中那样使用 -webkit- 和 -moz- 前缀。这可以启用特定浏览器实验中的特性。同时记住它是支持IE8+。


position属性

position属性值

static
元素框正常生成。块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创建一个或多个行框,置于其父元素中。
DEMO-1(static):

1
2
3
.static {
position: static;
}

relative
元素框偏移某个距离。元素仍保持其未定位前的形状,它原本所占的空间仍保留。
DEMO-2(relative):

1
2
3
4
5
6
7
8
9
10
.relative1 {
position: relative;
}
.relative2 {
position: relative;
top: -20px;
left: 20px;
background-color: white;
width: 500px;
}

absolute
元素框从文档流完全删除,并相对于其包含块定位。包含块可能是文档中的另一个元素或者是初始包含块。元素原先在正常文档流中所占的空间会关闭,就好像元素原来不存在一样。元素定位后生成一个块级框,而不论原来它在正常流中生成何种类型的框。
absolute 是最棘手的position值。 absolute 与 fixed 的表现类似,除了它不是相对于视窗而是相对于最近的“positioned”祖先元素。
如果绝对定位(position属性的值为absolute)的元素没有“positioned”祖先元素,那么它是相对于文档的 html 标签 (参考的文档说是相对于文档的 body 元素,之后我将会说为什么我认为是相对html标签),并且它会随着页面滚动而移动。
记住一个“positioned”元素是指position 值不是 static 的元素。
DEMO-3(absolute):

1
2
3
4
5
6
7
8
9
10
11
12
.relative {
position: relative;
width: 600px;
height: 400px;
}
.absolute {
position: absolute;
top: 120px;
right: 0;
width: 300px;
height: 200px;
}

为什么上面我说绝对定位子元素在没有“positioned”祖先元素时是相对 html 标签 而不是 body元素呢?我们修改一下上例把position:relative 的div 改成 position:static,结果如下:

absolute的元素的top为120px;以下截图一目了然:
position-absolute1
position-absolute2
所以我认为是相对于html标签才对。。。

fixed
元素框的表现类似于将 position 设置为 absolute,不过其包含块是视窗本身。即便页面滚动,它还是会停留在相同的位置。
DEMO-4(fixed):

1
2
3
4
5
6
7
.fixed {
position: fixed;
bottom: 0;
right: 0;
width: 200px;
background-color: white;
}

一个固定定位元素不会保留它原本在页面应有的空隙。

令人惊讶地是移动浏览器对 fixed 的支持很差。这里有相应的解决方案

position例子-左固定宽度,右自适应宽度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.container {
position: relative;
}
nav {
position: absolute;
left: 0px;
width: 200px;
}
section {
/* position is static by default */
margin-left: 200px;
}
footer {
position: fixed;
bottom: 0;
left: 0;
height: 70px;
background-color: white;
width: 100%;
}
body {
margin-bottom: 120px;
}

这个例子在容器比nav元素高的时候可以正常工作。如果容器比nav元素低,那么nav会溢出到容器的外面。之后我们会讨论下其他布局技术,它们都各有优劣。


float

float很熟悉了,不举例了。可以用作文字环绕图片,float布局很常用。
其中、最棘手的应该算是清除浮动了。

如何清除浮动?

float例子-左固定宽度,右自适应宽度

1
2
3
4
5
6
7
nav {
float: left;
width: 200px;
}
section {
margin-left: 200px;
}

给最外的框框添加清除浮动的class:

1
2
3
4
5
6
7
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}

百分比宽度

百分比是一种相对于包含块的计量单位。它对图片很有用:如下我们实现了图片宽度始终是容器宽度的50%。把页面缩小看下效果!

1
2
3
4
article img {
float: right;
width: 50%;
}

图片要放在文字前哦。不然就没有图片在文字右边这种效果啦…
再复习一遍,别忘了给article元素加清除浮动的class:

1
2
3
4
5
6
7
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}

百分比宽度布局-左固定百分比右自适应

在下面的例子中,当窗口宽度很窄时 nav 的内容会以一种不太友好的方式被包裹起来。总而言之,选一种最合适你的内容的方式。
下面例子 与 float例子-左固定宽度,右自适应宽度 这个例子基本一样,就是把像素换成百分比。

1
2
3
4
5
6
7
nav {
float: left;
width: 25%;
}
section {
margin-left: 25%;
}

还是别忘了清除浮动。

以上做法不是很优雅,接下来来看一种更酷的做法~

媒体查询

“响应式设计(Responsive Design)”是一种让网站针对不同的浏览器和设备“响应”不同显示效果的策略,这样可以让网站在任何情况下显示的很棒!

媒体查询是做此事所需的最强大的工具。让我们使用百分比宽度来布局,然后在浏览器变窄到无法容纳侧边栏中的菜单时,把布局显示成一列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@media screen and (min-width:600px) {
nav {
float: left;
width: 25%;
}
section {
margin-left: 25%;
}
}
@media screen and (max-width:599px) {
nav li {
display: inline;
}
}

还是别忘了清除浮动。

当屏幕宽度大于等于 600px 时会使用这段CSS:

1
2
3
4
5
6
7
8
9
@media screen and (min-width:600px) {
nav {
float: left;
width: 25%;
}
section {
margin-left: 25%;
}
}

否则将使用这段CSS:

1
2
3
4
5
@media screen and (max-width:599px) {
nav li {
display: inline;
}
}

现在我们的布局在移动浏览器上也显示的很棒。这里有一些 同样使用了媒体查询的著名站点。在MDN文档中你还可以学到更多有关媒体查询的知识。

:使用 meta viewport 之后可以让你的布局在移动浏览器上显示的更好。关于移动web的总结实践我将在不久的将来整理 O(∩_∩)O~


inline-block

你可以创建很多网格来铺满浏览器。在过去很长的一段时间内使用 float 是一种选择,但是使用 inline-block 会更简单。让我们看下使用这两种方法的例子:

困难的方式(使用浮动):

1
2
3
4
5
6
7
8
9
.box {
float: left;
width: 200px;
height: 100px;
margin: 1em;
}
.after-box {
clear: left;
}

容易的方式(使用 inline-block):

你可以用 display 属性的值 inline-block 来实现相同效果。

1
2
3
4
5
6
.box2 {
display: inline-block;
width: 200px;
height: 100px;
margin: 1em;
}

了解更多:IE6和IE7支持 inline-block

inline-block 布局-左固定百分比右自适应

使用 inline-block 来布局。有一些事情需要你牢记:

  • vertical-align 属性会影响到 inline-block 元素,你可能会把它的值设置为 top 。
  • 你需要设置每一列的宽度
  • 如果HTML源代码中元素之间有空格,那么列与列之间会产生空隙

DEMO:

1
2
3
4
5
6
7
8
9
10
nav {
display: inline-block;
vertical-align: top;
width: 25%;
}
.column {
display: inline-block;
vertical-align: top;
width: 75%;
}

CSS3属性-column

这里有一系列新的CSS属性,可以帮助你很轻松的实现文字的多列布局。让我们瞧瞧:

1
2
3
4
5
6
7
8
9
.three-column {
padding: 1em;
-moz-column-count: 3;
-moz-column-gap: 1em;
-webkit-column-count: 3;
-webkit-column-gap: 1em;
column-count: 3;
column-gap: 1em;
}

CSS columns是很新的标准,所以你需要使用前缀,并且它不被IE9及以下和Opera Mini支持。还有许多和 cloumn 相关的属性,点击这里了解更多

flexbox

新的 flexbox 布局模式被用来重新定义CSS中的布局方式。很遗憾的是最近规范变动过多,导致各个浏览器对它的实现也有所不同。不过我仍旧想要分享一些例子,来让你知道即将发生的改变。这些例子目前只能在支持 flexbox 的 Chrome 浏览器中运行,基于 最新的标准

网上有不少过时的 flexbox 资料。 如果你想要了解更多有关 flexbox 的内容,从这里学习如何辨别一份资料是否过时。此参考文献作者已经写了一份关于最新标准的详细文章

使用flexbox你还可以做的更多;这里只是一些让你了解概念的例子:

使用 Flexbox 的简单布局

1
2
3
4
5
6
7
8
9
10
11
.container {
display: -webkit-flex;
display: flex;
}
nav {
width: 200px;
}
.flex-column {
-webkit-flex: 1;
flex: 1;
}

使用 Flexbox 的牛逼布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.container {
display: -webkit-flex;
display: flex;
}
.initial {
-webkit-flex: initial;
flex: initial;
width: 200px;
min-width: 100px;
}
.none {
-webkit-flex: none;
flex: none;
width: 200px;
}
.flex1 {
-webkit-flex: 1;
flex: 1;
}
.flex2 {
-webkit-flex: 2;
flex: 2;
}

使用 Flexbox 的居中布局

1
2
3
4
5
6
7
8
.vertical-container {
display: -webkit-flex;
display: flex;
height: 300px;
}
.vertically-centered {
margin: auto;
}

参考文献:
[1] 学习CSS布局
[2] CSS 框模型( Box module )
[3] CSS 框模型概述
[4] 网页布局基础

文章目录
  1. 1. 如何设置块级元素水平居中?
    1. 1.1. 方法一(差):设置width + margin
    2. 1.2. 方法二(可):设置max-width + margin
  2. 2. 盒子模型
    1. 2.1. 盒子模型的结构
    2. 2.2. 外边距折叠( Collapsing margins )
      1. 2.2.1. 折叠后 margin 的计算
      2. 2.2.2. 不发生margin折叠的情况
    3. 2.3. 浮动元素、inline-block 元素、绝对定位元素
      1. 2.3.1. 创建了块级格式化上下文的元素
      2. 2.3.2. 元素自身的margin折叠
    4. 2.4. 内容的尺寸与元素框的总尺寸
    5. 2.5. CSS3属性:box-sizing
  3. 3. position属性
    1. 3.1. position属性值
    2. 3.2. position例子-左固定宽度,右自适应宽度
  4. 4. float
    1. 4.1. 如何清除浮动?
    2. 4.2. float例子-左固定宽度,右自适应宽度
  5. 5. 百分比宽度
    1. 5.1. 百分比宽度布局-左固定百分比右自适应
  6. 6. 媒体查询
  7. 7. inline-block
    1. 7.1. inline-block 布局-左固定百分比右自适应
  8. 8. CSS3属性-column
  9. 9. flexbox
    1. 9.1. 使用 Flexbox 的简单布局
    2. 9.2. 使用 Flexbox 的牛逼布局
    3. 9.3. 使用 Flexbox 的居中布局