CSS基础:块级元素与盒模型

时间:2024-01-23 09:51:42

简介

  在 HTML4.01 中,元素通常可以分为块级元素( "Block-level element" ) 和内联元素 ( "Inline-level element" ) 两大类。块级元素单独占一行显示,内部可以包含内联元素或其他块级元素;内联元素不换行,内部只能包含其他内联元素,在这篇文章中将只讨论块级元素。

(:在 HTML5 中并没有块级元素和内联元素的概念,而是通过内容模型( "Content model" )规定了每个元素的分类( "Content categories" )和允许包含的内容( "Permitted content" ),例如:<a> 标签在 HTML4.01 中是内联元素,理论上不能嵌套诸如 <div> 之类的块级元素,但是在 HTML5 中判断是否合法要稍微复杂一点: <a> 标签的分类可能属于流元素( "Flow content" )或短语元素( "Phrasing content" ),交互元素( "Interactive content" ),可触元素( "palpable content" )中的一种或多种,具体情况要根据上下文而定,允许包含的内容是 "transparent",意为透明的,也就是说既可以包含 "Flow content" 又可以包含 "Phrasing content" ,根据父元素决定,如果单独像 "a > div" 这样嵌套,由于 <div> 标签的分类属于 "Flow content",因此这里是合法的,如果像 "p > ins > a > div" 这样嵌套,"a > div" 是否合法要看 "ins > div" 是否合法,由于 <ins> 允许包含的内容也是 "transparent",所以再看 "p > div" 是否合法,由于 <p> 允许包含的内容只能是 "Phrasing content",所以总的来说这里是不合法的)

 

  还需要注意的是:块级元素和 CSS 中 { display: block; } 的元素不是一个概念,例如,<li> 元素默认的 display 值为 list-item,<table> 元素默认的 display 值为 table ,但是它们都是块级元素,具有块级元素的基本特征,在同一个水平流上只能显示一个元素。

 

  块级元素总是被表示为一个矩形的盒子,称为 "盒模型",由 "外边距+边框+内边距+盒子本身宽高" 组成,如图所示:

"盒子本身宽高" 规定的部分称为内容区域 "Content box",在 CSS 中设置的 "width" 和 "height" 就是作用于这个区域;

"盒子本身宽高+内边距" 规定的部分称为内边距区域 "Padding box",在 CSS 中设置的 "background" 就是作用于这个区域;

"盒子本身宽高+内边距+边框" 规定的部分称为边框区域 "Border box";

"盒子本身宽高+内边距+边框+外边距" 规定的部分称为外边距区域 "Margin box";

利用 CSS3 的 "border-sizing" 属性可以更改 "width" 和 "height" 的作用区域,理论上讲有如下四种情况:

{ box-sizing: content-box; }    /* 默认 */

{ box-sizing: padding-box; }    /* 火狐曾经支持 */

{ box-sizing: border-box; }    /* 全部支持 */

{ box-sizing: margin-box; }    /* 不支持 */

"border-sizing" 属性被所有现代浏览器支持,IE 家族只有 IE8 以上才支持,并且需要添加各个浏览器的私有前缀。

 

块级元素的水平格式化

  具体表现为:正常流中的块级元素其水平部分的总和等于父容器的宽度,也就是说:左外边距+左边框+左内边距+宽度+右内边距+右边框+右外边距 = 父容器的宽度。这条规则主要涉及到 "margin","padding","border","width" 四个属性,其中 "margin" 和 "padding" 的默认值均为0,"border" 的默认值为 "none","width" 的默认值为 "auto",意为补齐,并且只有 "width","margin" 的值可以设置为 "auto",它们又有以下几种特殊情况:(仅讨论水平方向上,"margin" 仅代表 "margin-left" 和 "margin-right")

"width" 和 "margin" 均固定:这种情况又称为格式化属性过分受限( "overconstrained" ),此时浏览器总会将 "margin-right" 强制为 "auto" 以撑满父容器;
"width" 值固定,"margin-left" 或 "margin-righ" 只有一侧值固定:浏览器表现为将另一侧 "margin" 的值强制为 "auto" 以撑满父容器;
"width" 值为 "auto",两侧 "margin" 值固定:浏览器表现为 "width" 撑满父容器除 "margin" 外的剩余宽度;
"width" 值固定,两侧 "margin" 值为 "auto":浏览器表现为 "margin-right" 和 "margin-left" 平分剩余宽度以撑满父容器,借用这种方法可以使块级元素水平居中;
"width" 和 "margin" 均为 "auto":浏览器表现为 "width" 撑满父容器,"margin" 为0,并且只要 "width" 设置为 "auto",无论是 "margin-left" 还是 "margin-right" 被设置为 "auto",它们最后都会变成0;

根据这一准则,以及创造者背后的意图,我们应该少设置盒子的宽度,避免其丢失流动性。

 

块级元素的垂直格式化

  具体表现为:块级元素的高度会尽可能小,直到可以包裹其中的内容,或者也可以理解为块级元素的高度由它的内容撑开。在垂直方向上,不但 "height" 的表现与 "width" 有区别,垂直方向的 "margin" 设置为 "auto" 时与水平方向的 "margin" 也不同,它将自动计算为0,另外垂直方向的 "margin" 会发生合并现象:
相邻兄弟元素之间上者的 "margin-bottom" 和下者的 "margin-top" 合并,可以通过触发 BFC 或在中间插入一个内联元素阻断,防止合并发生;
父容器和它的第一个子元素的 "margin-top" 合并,可以通过触发 BFC 或在中间插入一个内联元素阻断,防止合并发生,另外也可以设置父容器的 "border" 或 "padding" 进行阻断,因为它们可以将两者的 "margin" 分开,而子元素的就不行;
父容器和它的最后一个子元素的 "margin-bottom" 合并,避免方法同上;
合并的规则是:"正正取最大","负负取最小","正负则相加"。

同样,根据这一准则,我们应该少设置盒子的高度,也是避免其丢失流动性。总的来说就是:页面元素的宽度由外到内自适应,高度由内到外撑开。

 

关于 width 和 height

  上面已经说了,尽量避免将 "width" 和 "height" 的值设置为固定,除此之外,还有一种流动性更好的替代方案,即 "min-width","max-width" 和 "min-height","max-height",并且这四个属性的兼容性非常好,兼容 IE8 以上以及所有现代浏览器,需要注意的是,它们和 "width","height" 之间有一套独立的覆盖规则,与常规的 CSS 优先级无关:
即使 "width" 设置了 "!important" ,如果它超过了最大宽度,依然会被后者覆盖,或者说截断;
当 "max-width" 和 "min-width" 冲突时,"min-width" 的权重更大,与优先级无关;

示例:

.test {
    width: 100px !important;
    max-width: 50px; /* 最终结果为50px */
}

 

.test {
    width: 100px !important;
min-width: 70px; /* 最终结果为70px */ max-width: 50px; }

 

关于 padding

  关于 "padding" 要说的只有两点:一是 "padding" 不能设置为负值,二是无论是水平还是垂直方向,"padding" 的百分比值都是基于父容器的宽度计算的。

示例:

<!-- html -->
<div class="father">
    <div class="son"></div>
</div>

 

/* css */
.father {
    width: 200px;height: 100px;
    background: red;
}
.son {
    width: 50px;height: 50px;
    padding: 25%;  /* 最终结果为50px */
    background: green;
}

 

关于 border

  "border-color" 有一个很重要的特性,其默认值是 "transparent",但是当设置了 "color" 后,其计算结果为 "color" 设置的颜色,拥有类似特性的属性还有 "outline","box-shadow","text-shadow" 等。

示例:

.test {
    border: solid 1px;  /* 边框颜色为红色 */
    color: red;
}

 

关于 margin

  和 "padding" 属性一样,"margin" 的百分比值也是基于父容器的宽度计算的,但是 "margin" 的值却可以设置为负值,并且 "-margin" 有着相当大的作用:
一是处于文档流中的元素,当 "margin-top" 和 "margin-left" 设置为负值时,元素向着对应方向移动;当 "margin-bottom" 和 "margin-right" 设置为负值时,元素本身不动,而是将后面的元素拉过来,这时文档流中堆叠顺序总是遵循默认的后来者居上的原则,也就是说后面的元素会覆盖前面的元素。
二是处于文档流中的元素,如果先设置了 "position:relative" 和 "z-index" 改变堆叠顺序,那么覆盖规则由 "z-index" 的大小决定。
三是使用 "position:absolute" 脱离文档流的元素,当 "margin-top" 和 "margin-left" 设置为负值时,元素向着对应方向移动;当 "margin-bottom" 和 "margin-right" 设置为负值时,元素本身不动,对后面的元素也没有影响。
四是使用 "float" 脱离文档流的元素,如果负 "margin" 的方向与浮动方向相同,那么元素向着对应方向移动;相反,那么元素本身不动,而是将前面或者后面的元素拉过来。
五是当元素的 "width" 为 "auto" 时,负 "margin" 可以增大元素的宽度,使其超出父容器的宽度。