3.1 盒子模型概述
盒子模型是CSS 的基石之一,它指定元素如何显示以及(在某种程度上)如何相互交互.页面上的每个元素被看做一个矩形框,这个框由元素的内容/内边距/边框和外边距组成.
内边距出现在内容区域的周围.如果在元素上添加背景,那么背景会应用于由内容和内边距组成的区域.因此,我们常常使用内边距在内容周围创建隔离带,是内容不会与背景混在一起.添加边框会在内边距的区域外添加一条线.这些线可以有多种样式,比如实线/虚线/点线.在边框外边的外边距.外边距是透明的.一般使用它控制元素之间的隔离.
内边距/边框/外边距都是可选的,默认值为零.但是,许多元素将又用户代理样式设置外边距和内边距.可以通过将元素的margin或padding设置为零来覆盖这些浏览器样式.这可以分别进行,也可以使用通用选择器对所有元素进行设置:
* {
margin: 0;
padding: 0;
}
请记住,这种技术不分元素,所以它对option等元素有不利影响.因此,使用全局reset把内边距和外边距显示的设置为零可能更安全.
在CSS中,width和height指的是内容区域的宽度和高度.增加内边距/边框/外边距不会影响内容的尺寸,但是会增加元素框的总尺寸.假设框的每个边上有10像素的外边距和5像素的内边距,如果希望这个框达到100像素宽,就需要将内容的宽度设置为70像素.
#mybox {
margin: 10px;
padding: 5px;
width: 70px;
}
3.1.1 外边距叠加
外边距是一个相当简单的概念.但是,在实践中对网页进行布局时,它会造成许多混淆.简单的说,当两个或更多外边距相遇时,他们将形成一个外边距.这个外边距的高等于两个发生叠加的外边距的高度较大者.
当一个元素出现在两一个元素上面时,第一个元素的底边与第二个元素的顶外边距发生叠加.
当一个元素包含在另一个元素中时(假设没有内边距或边框将外边距分开),它们的顶或底外边距也会发生叠加.
尽管初看上去有点奇怪,但是外边距甚至可以与本身发生叠加.假设有个空元素,它有外边距,但是没有边框和内边距.在这种情况下,顶外边距和底外边距就碰到了一起,它们会发生叠加.
如果这个外边距碰到另一个元素的外边距,它还会发生叠加.
这就是一系列空的段落元素占用空间非常小的原因,因为它们的所有外边距都叠加到一起,形成一个小的外边距.
外边距叠加初看上去可能有点儿奇怪,但是它实际上有重要意义.以由几个段落组成的典型文本页面为例.第一个段落上面的空间等于段落的顶外边距.如果没有外边距叠加,后续所有段落的空间将是相邻外边距和底边距的和.这意味着段落之间的空间是页面顶部的两倍.如果发生外边距叠加,段落之间的顶外边距和底外边距就叠加在一起,这样各处的距离就一致了.
注意:只有普通文档流中块框的垂直外边距才会发生叠加.行内框/浮动框/绝对定位框之间的外边距不会发生叠加.
3.2 定位概述
既然已经熟悉了盒模型,我们就来看看可视化模型和定位模型.理解这两个模型的细微差异是非常重要的,因为它们控制着如何在页面上布置每个元素.
3.2.1 可视化格式模型
p/h1/div等元素常常被称为块级元素.这意味着这些元素显示为一块内容,即"块框".与之相反,strong/span等元素被称为行内元素,因为它们的内容显示在行中,即"行内框".
可以使用display属性改变生成的框的类型.这意味着,通过将display属性设置为block,可以让行内元素(比如锚)表现得想块级元素一样.还可以通过将display属性设置为none,让生成的元素根本没有框.这样这个框机器所有内容就不在显示,不占用文档中的空间.
CSS中有3种基本定位机制:普通流/浮动/绝对定位.除非专门制定,否则所有框都在普通流中定位.顾名思义,普通流中元素框的位置由元素在HTML中的位置决定.
块级框从上到下一个接一个地垂直排列,框之间的垂直距离有框的垂直外边距计算出来.
行内框在一行中水平排列.可以使用水平内边距/边框/外边距调整它们之间的水平间距.但是,垂直内边距/边框/外边距不影响行内框的高度.同样,在行内框上设置显式的高度或宽度也没有影响.由一行形成的水平框称为行框,行框的高度总是足以容纳它包含的所有行内框.但是,设置行高可以增加这个框的高度.因此,修改行内框尺寸的唯一方法是修改行高或者水平边框/内边距或外边距.
框可以按照HTML元素的嵌套方式包含其他框.大多数框由显式定义的元素形成.但是,在一种情况下,即使没有进行显式定义,也会创建块级元素.这种情况发生在将一些文本添加到一个块级元素(比如div)的开头时.即使没有把这些文本定义为块级元素,它也会被当成块级元素对待:
<div>
some text
<p>Some more text</p>
</div>
在这种情况下,这个框被称为匿名框,因为它不与专门定义的元素相关联.
块级元素内的文本行也会发生类似的情况.假设有一个包含3行文本的段落.每行文本形成一个匿名框.无法直接对匿名块或行框应用样式,除非使用不常用的:first-line伪元素.但是,这有助于理解在屏幕上看到的所有东西形成某种框.
3.2.2 相对定位
相对定位是一个非常容易掌握的概念.如果对一个元素进行相对定位,它将出现在它所在的位置上.然后,可以通过设置垂直或水平位置,让这个元素"相对于"它的起点移动.如果将top设置为20像素,那么框将出现在原始位置顶部下面20像素的地方.如果将left设置为20像素,那么会在元素左边创建20像素的空间,也就是将元素向右移动.
#myBox {
position: relative;
left: 20px;
top: 20px;
}
在使用相对定位时,无论是否移动,元素仍然占据原来的空间.因此,移动元素会导致它覆盖其他框.
3.2.3 绝对定位
相对定位实际上被看做普通流定位模型的一部分,因为元素的位置是相对于它在普通流中的位置.与之相反,绝对定位使元素的位置与文档流无关,因此不占据空间.普通文档流中其他元素的布局就像绝对定位的元素不存在一样.
绝对定位的元素位置是相对于距离它最近的那个已定位的祖先元素确定的.如果元素没有定位的祖先元素,那么它的位置是相对于初始包含块的.根据用户代理的不同,初始包含块可能是画布或HTML元素.
与相对定位的框一样,绝对定位的框可以从它的包含块向上/下/左/右移动.这提供了最大的灵活性,你可以直接将元素定位在页面上的任何位置.
对于定位的主要问题是记住每种定位的意义,相对定位是"相对于"元素在文档流中的初始位置,而绝对定位是"相对于"距离它最近的已定位祖先元素,如果不存在已定位的祖先元素,那么就相对于初始包含块.
因为绝对定位与文档流无关,所以它们可以覆盖页面上的其他元素.可以通过设置z-index属性来控制这些框的叠放次序.z-index值越高,框在栈中的位置就越高.
相对于最近的已定位祖先元素来定位绝对定位的元素,能够实现一些非常有意思的效果.例如,假设希望让一个文本段落对准一个大框的右下角,只需对包含框进行相对定位,然后相对于这个框对段落进行绝对定位:
#branding {
width: 70em;
height: 10em;
position: relative;
}
#branding .tel {
position: absolute;
right: 1em;
bottom: 1em;
text-align: right;
}
<div id="branding">
<p>class="tel">Tel: 0845 838 6163</p>
</div>
在进行页面布局时,绝对定位非常有用,尤其是在使用相对定位的祖先元素的情况下.你完全可能只是用绝对定位就创建出整个设计.为此,这些元素需要具有固定尺寸,这样就能够将它们定位在任何地方而不会有重叠的风险.
因为绝对定位与文档流无关,所以它们不影响普通流中的框.如果扩大绝对定位的框(例如,增加字号),周围的框不会重新定位.因此,尺寸的任何改变都会导致绝对定位的框发生重叠,从而破坏精心调整过得布局.
固定定位
固定定位是绝对定位的一种.差异在于固定元素的包含块是视口(viewport).这使我们能够创建总是出现在窗口相同位置的浮动元素.
比如博客侧边栏设置固定定位:
side-bar {
float: left;
width: 20%;
position: fixed;
}
/*固定定位*/
3.2.4 浮动
最后一种可视化格式模型是浮动模型.浮动的框可以左右移动,直到它的外边缘碰到包含框或另一个浮动框的边缘.因为浮动框不在文档的普通流中,所以文档的普通流中的块框表现得就像浮动框不存在一样.
当把框1向右浮动时,它脱离文档流并且向右移动,直到它的右边缘碰到包含框的边缘.
当把框1向左浮动时,它脱离文档流并且向左移动,直到它的左边缘碰到包含框的左边缘.因为它不在处于文档流中,所以它不占据空间,实际上覆盖住了框2,使框2从视图中消失.如果把所有3个框都向左浮动,那么框1向左浮动直到碰到包含框,另外两个框向左浮动直到碰到前一个浮动框.
如果包含框太窄,无法容纳水平浮动的3个浮动元素,那么其他浮动块向下移动,直到有足够空间的地方.如果浮动元素的高度不同,那么当它们向下移动时可能会被其它浮动的元素卡住.
行框和清理
前一节指出,浮动会让元素脱离文档流,不在影响不浮动的元素.实际上,并不完全如此.如果浮动的元素后面有一个文档流中的元素,那么这个元素的框会表现得像浮动根本不存在 一样.但是,框的文本内容会受到浮动元素的影响,会移动以留出空间.用技术术语来说,浮动元素旁边的行框被缩短,从而给浮动元素留出空间,因此行框围绕浮动框.实际上,创建浮动框使文本可以围绕图像.
要想阻止行框围绕浮动框的外边,需要对包含这些行框的元素应用clear属性.clear属性的值可以是left/right/both/none,它表示框的那边不应该挨着浮动框.我以前总是认为clear属性会自动地抵消前面的浮动.但是,实际情况有意思的多.在清理元素时,浏览器在元素顶上添加足够的外边距,使元素的顶边缘垂直下降到浮动框下面.
浮动元素脱离了文档流,不影响周围的元素.但是,对元素的清理实际上为前面的浮动元素留出了垂直空间.
这是一个有用的布局工具,它让周围的元素为浮动留出空间.这解决了前面你看到的绝对定位的问题------垂直高度的改变不影响周围的元素,从而破坏了设计.让我们来更详细地看看浮动和清理.假设有一个图片,你想让它浮动到一个文本块的左边.你想将这个图片和文本包含在另一个具有背景颜色和边框的元素中.你可能会编写下面这样的代码:
.news {
baclgroung-color: gray;
border: 1px solid black;
}
.news img {
float: left;
}
.news p {
float: right;
}
<div class="news">
<img src="/img/news-pic.jpg" alt="my pic" />
</div>
但是,因为浮动元素脱离了文档流,所以包围图片和文本的div不占据空间.如何让包围元素在视觉上包围浮动元素呢?需要在这个元素中的某个地方应用clear.可惜这个示例中没有现有的元素可以清理,所以需要在最后一个段落下面添加一个空元素并且清理它.
.news {
background-color: gray;
border: 1px solid black;
}
.news img {
float: left;
}
.news p {
float: right;
}
.clear {
clear: both;
}
/*通过添加额外标签来清除浮动*/
<div class="news>
<img src="/img/news-pic.jpg" alt="my pic">
<p>Some text</p>
<br class="clear"/>
</div>
这会实现我们希望的效果,但是要添加不必要的代码.常常有现成的元素可以应用clear,但是有时候为了布局不得不忍受巨大的痛苦添加无意义的标记.
还可以不对浮动的文本和图像进行清理,而是选择浮动div容器:
.news {
background-color: gray;
border: 1px solid black'
float: left;
}
/*通过浮动div容器来清除浮动*/
.news img {
float: left;
}
.news p {
float: right;
}
<div class="news">
<img src="/img/news-pic.jpg" alt="my pic" />
<p>Some text</p>
</div>
这也会产生我们想要的结果.但是,下一个元素会受到这个浮动元素影响.为了解决这个问题,有些人选择浮动布局中的几乎所有东西,然后使用合适的元素(常常是站点的页脚)对这些浮动元素进行清理.这有助于减少或消除不必要的标记.但是,浮动会变得复杂,而且一些老式浏览器在处理有许多浮动元素的布局时有困难.因此,许多人喜欢添加少量的额外标记.
overflow属性定义在包含内容对于指定的尺寸太大的情况下元素应该怎么样.在默认情况下,内容会溢出到框外,进入相邻空间.应用值为hidden或auto的overflow属性有一个有用的副作用,这会自动地清理包含的任何浮动元素.因此这是一种有用的元素清理方法,不需要添加额外标记.这个方法并不适合所有情况,因为设置框overflow属性会影响它的表现.更具体的说,这种方法在某些情况下会产生滚动条或截断内容.
然后,一些人使用CSS生成的内容或JavaScript对浮动进行清理.这两种方法的基本概念是相同的,并不直接向标记中添加进行清理的元素,而是将它动态地添加到页面中.对于这两种方法,需要指定进行清理的元素应该出现在哪里,而且常常要添加一个类名:
<div class="new clear">
<img src="/img/news-pic.jpg" alt="my pic" />
<p>Some text</p>
</div>
在使用CSS方法时结合使用:after伪类和内容声明在指定的现有内容末尾添加新的内容占据垂直空间或者在页面上显示,所以它是个非常小的不引人注意的字符.因为不希望新内容占据垂直空间或者在页面上显示,所以需要将height设置为0,将visibility设置为hidden.因为被清理的元素在它们的顶外边距上添加了空间,所以生成的内容需要将它的display属性设置为block,这样设置之后,就可以对生成的内容进行清理:
.clear: after {
content: ".";
height: 0;
visitiblity: hidden;
display: block;
clear: both;
}
/*使用伪类元素清除浮动(推荐使用)*/