5

2017-07-20: 关于外边距折叠, 推荐问题: https://segmentfault.com/q/10...

8 盒模型 Box Model

URL: http://www.w3.org/TR/CSS2/box...

Translator : HaoyCn

Date: 15th of Aug, 2015

译者注:本译文仅择精要部分翻译了规范,主要描述了盒模型结构,以及重点分析外边距折叠。个人水平有限,欢迎指正!

CSS盒模型所描述的矩形盒由文档树内的元素生成,根据视觉格式化模型布局。

8.1 盒尺寸 Box Dimensions

每个盒都有一个内容区域 Content (如,文本,图片等)以及可选的围绕在周围的内边距、边框和外边距区域;每个区域的大小由本文后述的属性指定。下图展示了这些区域的关联以及用于描述外边距、边框和内边距的各部分的术语。

au9pGgL.png

外边距、边框和内边距可以被分解到上、右、下、左各部分(如,在上图中, LM 表示左外边距, RP 表示右内边距, TB 表示上边框等)。

四种区域(内容、内边距、边框、外边距)的边界被称作一个“边缘 Edge ”,因此每个盒有四种边缘:

内容边缘 Content Edge 或内边缘 Inner Edge

内容边缘围绕着由盒的宽和高所指定的矩形,该矩形通常由元素的已渲染内容 Rendered Content 所决定。四个内容边缘规定了盒的内容盒 Content Box

内边距边缘

内边距边缘围绕着盒的内边距。如果内边距宽度为0,则内边距边缘即是内容边缘。四个内边距边缘规定了盒的内边距盒 Padding Box

边框边缘

边框边缘围绕着盒的边框。如果边框宽度为0,则边框边缘即是内边距边缘。四个边框边缘规定了盒的边框盒 Border Box

外边距边缘或外边缘

外边距边缘围绕着盒的外边距。如果外边距宽度为0,则外边距边缘即边框边缘。四个外边距边缘规定了盒的外边距盒 Margin Box

每个边缘都可以被分解成上、右、下、左边缘。

盒内容区域的尺寸——即内容宽度 Content Width 和内容高度 Content Width ——由这些因素所决定:生成盒的元素是否设置了 width height 属性;盒是否包含了文本或其他盒;盒是否为表格;等等。盒的宽度和高度将在视觉格式化模型详述一章中讨论。

盒的内容、内边距以及边框区域的背景样式由生成盒的元素的 background 属性所规定。外边距的背景始终为透明。

8.2 外边距、内边距和边框的例子

下例展示了外边距、内边距和边框如何交互。HTML文档:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Examples of margins, padding, and borders<title>
<style type="text/css">
   ul { 
      background: yellow; 
      margin: 12px 12px 12px 12px;
      padding: 3px 3px 3px 3px;
      /* 未设置边框 */
   }
   li { 
      color: white;/* 文本颜色为白色 */ 
      background: blue;/* 内容和内边距背景为蓝色 */
      margin: 12px 12px 12px 12px;
      padding: 12px 0px 12px 12px; /* 注意右内边距为0 */
      list-style: none/* 列表前没有符号 */
      /* 未设置边框 */
   }
   li.withborder {
      border-style: dashed;
      border-width: medium;/* 各边均设置边框 */
      border-color: lime;
   }
</style>
</head>
<body>
   <ul>
      <li>First element of list</li>
      <li class="withborder">Second element of list is a bit longer to illustrate wrapping.</li>
   </ul>
</body>
</html>

该文档结果为文档树中(省略其他关系)一个 ul 元素及其两个 li 子元素。

下面的第一图展示了例子的结果。第二图展示了 ul 元素及其 li 子元素的外边距、内边距和边框之间的关系。(图片不成比例)

bKuRLle.png

注意:

  • 每个 li 盒的内容宽度是从上到下计算的;所有 li 盒的包含块由 ul 元素创建。

  • 每个 li 盒的外边距盒高度由其内容高度加上上下内边距、边框、外边距所决定。需要留意的是 li 盒间的垂直外边距发生了折叠。

  • li 盒的右内边距宽度被设为零( padding 属性)。效果如第二图所示。

  • li 盒的外边距是透明的——外边距总为透明——所以 ul 的内边距和内容区域的背景颜色(黄)穿透外边距显示了出来。

  • 第二个 li 元素指定了虚线边框( border-style 属性)。

8.3 外边距各属性

外边距的各属性规定了盒的外边距区域的宽度。 margin 设置所有四个方向的外边距,而其他外边距属性则只设置各自方向宽度。这些属性应用于所有元素,但垂直外边距在非替代行内元素上无效。

译者注:此处以及下文的各属性介绍均略,可查CSS手册

8.3.1 外边距折叠

在CSS中,两个及以上的(不一定是同胞)盒的相邻外边距可能合并为一个单独的外边距。以这种方式的合并的外边距被称为折叠 Collapse ,合并后的外边距被称为折叠外边距 Collapsed Margin

相邻垂直外边距发生折叠,除了:

  • 根元素的盒的外边距不折叠

  • 如果一个有空隙的元素的上下外边距相邻,其外边距将同其后同胞的相邻外边距折叠,但不同父块的下外边距折叠。

水平外边距不重叠。

两个外边距为相邻关系,当且仅当:

  • 是同属一个块格式化上下文的文档流内块级盒

  • 没有行盒、空隙、内边距和边框分隔它们(注意某些零高度行盒会因此而被忽略(见9.4.2章))

  • 盒边缘垂直相邻,也就是说,满足以下形式之一:

  • 盒上外边距及其第一个文档流内子盒的上外边距

  • 盒下外边距及下一个文档流内的同胞盒的上外边距

  • 如果父盒的高度计算值为 auto ,其最后一个文档流内子盒的下外边距及父盒的下外边距

  • 如果一个盒不建立新的块格式化上下文、 min-height 计算值为零、 height 计算值为零或 auto 、没有在文档流内的子盒,其上下外边距

如果一个折叠外边距与另一外边距的任何一边相邻,则视二者相邻。

注意:不是同胞或祖先关系的元素也可以产生相邻外边距。

注意:上述规则表明了:

  • 浮动盒的外边距不同其他任何盒折叠(甚至浮动及其文档流内的子元素也不折叠)

  • 创建了新的块格式化上下文的元素(如浮动、 overflow 不为 visible 的元素)的外边距不同其在文档流内的子元素外边距折叠

  • 绝对定位盒的外边距不同其他任何盒折叠(甚至不同其文档流内的子元素折叠)

  • 行内块盒的外边距不同其他任何盒折叠(甚至不同其文档流内的子元素折叠)

  • 文档流内块级元素的下外边距始终同其下一个文档流内的块级同胞的上外边距折叠,除非该对同胞之间有空隙。

  • 文档流内块元素如果没有上边框和上内边距,其第一个文档流内块级子元素没有空隙,二者的上外边距折叠。

  • 文档流内 height auto min-height 为零、没有下内边距和下边框的块盒,如果其最后一个文档流内块级子盒的下外边距没有同一个有空隙的上外边距折叠,二者下外边距折叠。

  • 如果某盒的 min-height 属性为零、没有上下边框和上下内边距、其 height 为0或 auto 、没有包含行盒、其所有的文档流内子元素外边距(如果有)折叠,则折叠其外边距。

当两个及以上外边距折叠,合并后的外边距宽度是发生折叠的外边距中的最大宽度。如果发生折叠的外边距中有负数,则为最大正数相邻外边距减去最小负数相邻外边距的绝对值。如果不存在正数外边距,则为零减去最小负数相邻外边距的绝对值。

如果一个盒的上下外边距相邻,则外边距可能穿过盒而折叠 Collapse Through It 。这种情况下,元素的定位取决于它同其他外边距折叠的元素的关系。

  • 如果该元素的外边距同其父元素的上外边距折叠,则该盒的上边框边缘同其父元盒的上边框边缘相同。

  • 否则,要么该元素的父元素的外边距不折叠,要么只有父元素的下外边距折叠。上边框边缘位置是假定该元素下边框非零时的位置。

需要注意的是,被折叠穿过的元素的定位对与之外边距折叠的其他元素的定位无影响;其上边框边缘的定位仅用于布局其后代元素。

8.6 双向上下文 Bidirectional Context 中行内元素的盒模型

对每个行盒而言,用户代理必须按视觉顺序(而非逻辑顺序)渲染其生成的行内盒的外边距、边框和内边距。

当元素 direction 属性值为 ltr ,元素呈现的第一个行盒的最左生成盒拥有左外边距、左边框和左内边距,而元素呈现的最后一个行盒的最右生成盒拥有右内边距、右边框和右外边距。

当元素 direction 属性值为 rtl ,元素呈现的第一个行盒的最右生成盒拥有右外边距、右边框和右内边距,而元素呈现的最后一个行盒的最左生成盒拥有左内边距、左边框和左外边距。

译者之思

译者读毕此文,细心揣摩,将经验和疑问总结如下:

一、两种盒模型

本章节描述了W3C的标准盒模型,同时还存在IE6在怪异模式 Quicks Mode 的另一种盒模型。此处简述二者的区别如下——

W3C标准下:盒总宽/高度 = width/height + padding + border + margin

怪异模式下:盒总宽/高度 = width/height + margin = 内容宽/高度 + padding + border + margin

CSS3中, box-sizing 默认为 content-box ,即采用W3C标准盒模型,若取值 border-box 则采用怪异模式盒模型。

二、不透明的外边距

CSS规范道:

盒的内容、内边距以及边框区域的背景样式由生成盒的元素的 background 属性所规定。外边距的背景始终为透明。

但在根元素 html 上设置了外边距,并规定了背景,该背景仍铺满全屏。

如下CSS:

html {
margin: 50px;
background: #000;
}

body 同此理。译者暂不知其因。欢迎读者指教。

三、有空隙的元素

外边距折叠中,很多地方叙述了“有空隙的元素”,这是什么意思呢?其意义即是说,该元素清除了浮动。

在翻译视觉格式化模型一章中,W3C给出了清除浮动以及计算空隙宽度的的案例,译者建议读者认真阅读该部分,尤其关注:当空隙为负值时取消外边距折叠的情形。

点此阅读:http://segmentfault.com/a/119...

如果读者已经掌握清除浮动和空隙的知识,那就让我们来看一个有空隙的情景。

如果一个有空隙的元素的上下外边距相邻,其外边距将同其后同胞的相邻外边距折叠,但不同父块的下外边距折叠。

以下代码中, B 是浮动块,为清除其浮动, C 引入了空隙。

共同CSS:

html,body{padding:0;margin:0;}
/*横线,直观对比折叠情况*/
.line{height:50px;background:red;} 
.mt{margin-top:50px;}
.mb{margin-bottom:50px;}
#B{float:left;width:1px;height:1px;}
#C{clear:both;}

其外边距将同其后同胞的相邻外边距折叠:

HTML:

<body>
   <div id="A">
      <div id="B"></div>
      <div id="C" class="mb"></div>
      <div id="D" class="mb"></div>
      <div class="line"></div>
   </div>
 </body>

渲染结果是, C D 的外边距折叠。

不同父块的下外边距折叠

HTML:

 <body>
   <div id="A" class="mb">
      <div id="B"></div>
      <div id="C" class="mb"></div>
   </div>
   <div class="line"></div>
 </body>

渲染结果是, C 的外边距不同其父元素 A 的外边距折叠。

四、避免盒自身垂直外边距折叠

如果一个盒不建立新的块格式化上下文、 min-height 计算值为零、 height 计算值为零或 auto 、没有在文档流内的子盒,其上下外边距

由此可以得出几种避免盒自身上下外边距折叠的办法,简单列举如下:

  1. 建立新块格式化上下文,如 overflow: hidden

  2. 设置 min-height

  3. 设置固定高 height

  4. 添加文档流内(即非浮动、非绝对定位)子盒

需要注意最后一种办法,子盒要么有边框或内边距,要么有内容,否则父盒的自身垂直外边距同样会折叠。而如果子盒只有垂直外边距,该垂直外边距将同父盒的垂直外边距折叠,而不会阻止父盒自身垂直边距折叠。


残阳映枫红
6.1k 声望638 粉丝