CSS布局总结与实践
更新日期:
重在实践,把常用的布局及其实践总结在这备忘,方便以后查询和使用。
包含了 “如何设置块级元素水平居中” 、 “如何实现左固定宽度或百分比,右边自适应” 等常见问题。
和 “外边距折叠” 这类重要的概念。及各种常见的属性和布局。
PS:DEMO借助了jsfiddle而现在它需要翻墙才能访问,
因此DEMO的效果也需要翻墙才能访问 (-.-|||
如何设置块级元素水平居中?
方法一(差):设置width + margin
|
|
DEMO:
方法二(可):设置max-width + margin
|
|
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
|
|
CSS
|
|
在没有被非空内容、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 都是正值):
|
|
由上结果观察到:A 与 B 间距 100px;
结论:在 margin 都是正数的情况下,取其中 margin 较大的值为最终 margin 值。
DEMO-3(参与折叠的 margin 都是负值):
|
|
由上结果观察到:A 与 B 重叠部分高度 75px;
结论:当 margin 都是负值的时候,取的是其中绝对值较大的,然后,从 0 位置,负向位移。
DEMO-4(参与折叠的 margin 中有正值,有负值):
|
|
由上结果观察到:A 与 B 间距 50(px)=100+(-50);
结论:有正有负,先取出负 margin 中绝对值中最大的,然后,和正 margin 值中最大的 margin 相加。
DEMO-5(相邻的 margin 要一起参与计算,不得分步计算):
要注意,相邻的元素不一定非要是兄弟节点,父子节点也可以,即使不是兄弟父子节点也可以相邻。
而且,在计算时,相邻的 margin 要一起参与计算,不得分步计算。
|
|
为了方便观察结果我添加了一个 “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不折叠):
|
|
两个绿色的块儿之间,相距100px,显然B与A之间没有发生折叠,而若 B 和它的浮动包含块发生 margin 折叠的话,金色的条应该位于绿色块的最上方,显然,没有发生折叠。
创建了块级格式化上下文的元素
创建了块级格式化上下文的元素,不和它的子元素发生 margin 折叠
块级格式化上下文:http://www.w3.org/TR/CSS2/visuren.html#block-formatting
DEMO-7(以”overflow : hidden” 的元素为例):
|
|
若 B 和它的 “overflow:hidden” 包含块发生 margin 折叠的话,金色的条应该位于绿色块的最上方,此例中显然没有折叠。
元素自身的margin折叠
元素自身的 margin-bottom 和 margin-top 相邻时也会折叠
自身 margin-bottom 和 margin-top 相邻,只能是自身内容为空,垂直方向上 border、padding 为 0。
DEMO-8(元素自身的 margin-bottom 和 margin-top折叠):
|
|
由上结果观察到:红框框里面的div的margin-bottom 和 margin-top折叠了,因为如果不折叠他的高会是150px,折叠之后它的高为100px。红色框框div的宽为100px,结果刚好是个正方形。
内容的尺寸与元素框的总尺寸
在 CSS 中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。
假设框的每个边上有 10 个像素的外边距和 5 个像素的内边距。如果希望这个元素框达到 100 个像素,就需要将内容的宽度设置为 70 像素,请看下图。
|
|
当你设置了元素的宽度,实际展现的元素却能够超出你的设置:因为元素的边框和内边距会撑开元素。
DEMO:
|
|
以前有一个代代相传的解决方案是数学。CSS开发者需要用比他们实际想要的宽度小一点的宽度,需要减去内边距和边框的宽度。值得庆幸地是你不需要再这么做了…
CSS3属性:box-sizing
当你设置一个元素为 box-sizing: border-box; 时,此元素的内边距和边框不再会增加它的宽度。这里有一个与上例相同的例子,唯一的区别是两个元素都设置了 box-sizing: border-box;
DEMO:
|
|
此时两个div不含margin的width都为500px,这就和我们设置的值一样了。
既然没有比这更好的方法,一些CSS开发者想要页面上所有的元素都有如此表现。所以开发者们把以下CSS代码放在他们页面上:
|
|
这样可以确保所有的元素都会用这种更直观的方式排版。
既然 box-sizing 是个很新的属性,目前你还应该像我之前在例子中那样使用 -webkit- 和 -moz- 前缀。这可以启用特定浏览器实验中的特性。同时记住它是支持IE8+。
position属性
position属性值
static
元素框正常生成。块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创建一个或多个行框,置于其父元素中。
DEMO-1(static):
|
|
relative
元素框偏移某个距离。元素仍保持其未定位前的形状,它原本所占的空间仍保留。
DEMO-2(relative):
|
|
absolute
元素框从文档流完全删除,并相对于其包含块定位。包含块可能是文档中的另一个元素或者是初始包含块。元素原先在正常文档流中所占的空间会关闭,就好像元素原来不存在一样。元素定位后生成一个块级框,而不论原来它在正常流中生成何种类型的框。
absolute 是最棘手的position值。 absolute 与 fixed 的表现类似,除了它不是相对于视窗而是相对于最近的“positioned”祖先元素。
如果绝对定位(position属性的值为absolute)的元素没有“positioned”祖先元素,那么它是相对于文档的 html 标签 (参考的文档说是相对于文档的 body 元素,之后我将会说为什么我认为是相对html标签),并且它会随着页面滚动而移动。
记住一个“positioned”元素是指position 值不是 static 的元素。
DEMO-3(absolute):
|
|
为什么上面我说绝对定位子元素在没有“positioned”祖先元素时是相对 html 标签 而不是 body元素呢?我们修改一下上例把position:relative 的div 改成 position:static,结果如下:
absolute的元素的top为120px;以下截图一目了然:
所以我认为是相对于html标签才对。。。
fixed
元素框的表现类似于将 position 设置为 absolute,不过其包含块是视窗本身。即便页面滚动,它还是会停留在相同的位置。
DEMO-4(fixed):
|
|
一个固定定位元素不会保留它原本在页面应有的空隙。
令人惊讶地是移动浏览器对 fixed 的支持很差。这里有相应的解决方案。
position例子-左固定宽度,右自适应宽度
|
|
这个例子在容器比nav元素高的时候可以正常工作。如果容器比nav元素低,那么nav会溢出到容器的外面。之后我们会讨论下其他布局技术,它们都各有优劣。
float
float很熟悉了,不举例了。可以用作文字环绕图片,float布局很常用。
其中、最棘手的应该算是清除浮动了。
如何清除浮动?
float例子-左固定宽度,右自适应宽度
|
|
给最外的框框添加清除浮动的class:
|
|
百分比宽度
百分比是一种相对于包含块的计量单位。它对图片很有用:如下我们实现了图片宽度始终是容器宽度的50%。把页面缩小看下效果!
|
|
图片要放在文字前哦。不然就没有图片在文字右边这种效果啦…
再复习一遍,别忘了给article元素加清除浮动的class:
|
|
百分比宽度布局-左固定百分比右自适应
在下面的例子中,当窗口宽度很窄时 nav 的内容会以一种不太友好的方式被包裹起来。总而言之,选一种最合适你的内容的方式。
下面例子 与 float例子-左固定宽度,右自适应宽度 这个例子基本一样,就是把像素换成百分比。
|
|
还是别忘了清除浮动。
以上做法不是很优雅,接下来来看一种更酷的做法~
媒体查询
“响应式设计(Responsive Design)”是一种让网站针对不同的浏览器和设备“响应”不同显示效果的策略,这样可以让网站在任何情况下显示的很棒!
媒体查询是做此事所需的最强大的工具。让我们使用百分比宽度来布局,然后在浏览器变窄到无法容纳侧边栏中的菜单时,把布局显示成一列:
|
|
还是别忘了清除浮动。
当屏幕宽度大于等于 600px 时会使用这段CSS:
|
|
否则将使用这段CSS:
|
|
现在我们的布局在移动浏览器上也显示的很棒。这里有一些 同样使用了媒体查询的著名站点。在MDN文档中你还可以学到更多有关媒体查询的知识。
另:使用 meta viewport 之后可以让你的布局在移动浏览器上显示的更好。关于移动web的总结实践我将在不久的将来整理 O(∩_∩)O~
inline-block
你可以创建很多网格来铺满浏览器。在过去很长的一段时间内使用 float 是一种选择,但是使用 inline-block 会更简单。让我们看下使用这两种方法的例子:
困难的方式(使用浮动):
|
|
容易的方式(使用 inline-block):
你可以用 display 属性的值 inline-block 来实现相同效果。
|
|
inline-block 布局-左固定百分比右自适应
使用 inline-block 来布局。有一些事情需要你牢记:
- vertical-align 属性会影响到 inline-block 元素,你可能会把它的值设置为 top 。
- 你需要设置每一列的宽度
- 如果HTML源代码中元素之间有空格,那么列与列之间会产生空隙
DEMO:
|
|
CSS3属性-column
这里有一系列新的CSS属性,可以帮助你很轻松的实现文字的多列布局。让我们瞧瞧:
|
|
CSS columns是很新的标准,所以你需要使用前缀,并且它不被IE9及以下和Opera Mini支持。还有许多和 cloumn 相关的属性,点击这里了解更多。
flexbox
新的 flexbox 布局模式被用来重新定义CSS中的布局方式。很遗憾的是最近规范变动过多,导致各个浏览器对它的实现也有所不同。不过我仍旧想要分享一些例子,来让你知道即将发生的改变。这些例子目前只能在支持 flexbox 的 Chrome 浏览器中运行,基于 最新的标准。
网上有不少过时的 flexbox 资料。 如果你想要了解更多有关 flexbox 的内容,从这里学习如何辨别一份资料是否过时。此参考文献作者已经写了一份关于最新标准的详细文章。
使用flexbox你还可以做的更多;这里只是一些让你了解概念的例子:
使用 Flexbox 的简单布局
|
|
使用 Flexbox 的牛逼布局
|
|
使用 Flexbox 的居中布局
|
|
参考文献:
[1] 学习CSS布局
[2] CSS 框模型( Box module )
[3] CSS 框模型概述
[4] 网页布局基础