css中margin重叠和一些相关概念(包含块containing block、块级格式化上下文BFC、不可替换元素 non-replaced element、匿名盒Anonymous boxes )

时间:2024-01-02 08:12:26

  平时在工作中,总是有一些元素之间的边距与设定的边距好像不一致的情况,一直没明白为什么,最近仔细研究了一下,发现里面有学问:垂直元素之间的margin有有互相重叠的情况;新建一个BFC后,会阻止元素与外界元素的重叠现象。

  先了解几个概念:可替换元素、不可替换元素(non-replaced element)、包含块(containing block)、块级格式化上下文(BFC)。

可参考css2.1 中文规范

1、可替换元素与不可替换元素

  根据css1 中所述:所谓可替换元素就是浏览器根据元素的标签和属性,来决定元素的具体显示内容。例如浏览器会根据<img>标签的src属性的值来读取图片信息并显示出来,而如果查看(x)html代码,则看不到图片的实际内容;又例如根据<input>标签的type属性来决定是显示输入框,还是单选按钮等。html中的<img>、<input>、<textarea>、<select>、<object>都是替换元素。而现在,这个概念已经发生了变化,在新的规范中,html5涉及到的<video>、<canvas>、<menu>元素也被认为是替换元素。因此可以把“替换”理解为“嵌入”

  替换元素就可以理解为需要一些外部内容来嵌入它的空间的元素。

  而不可替换元素(non-replaced element)就是不需要外部内容来填充它的空间的元素。

2、包含块(containing block

  在 CSS2.1 中,很多框的定位和尺寸的计算,都取决于一个矩形的边界,这个矩形,被称作是包含块( containing block )。 一般来说,(元素)生成的框会扮演它子孙元素包含块的角色;我们称之为:一个(元素的)框为它的子孙节点建造了包含块。包含块是一个相对的概念,每个框关于它的包含块都有一个位置,但是它不会被包含块限制;它可以溢出(包含块)。包含块上可以通过设置 ‘overflow’ 特性达到处理溢出的子孙元素的目的。

3、块级元素和行内级元素

  块级元素:当元素的CSS属性displayblocklist-item或 table时,它是块级元素 block-level。块级元素会生成块级盒,块级盒参与块格式化上下文

     行内级元素:当元素的 CSS 属性 display 的计算值为 inlineinline-block 或 inline-table 时,称它为行内级元素

4块级格式化上下文(BFC)

  BFC,英文全称叫做Block Formatting contexts,中文叫块级格式化上下文。可以将它理解为一个箱子,这个箱子中的元素与外部元素隔离,箱子里的元素不会影响外部的元素,也不受外部元素的影响(利用这个特性可以消除浮动元素对其非浮动的兄弟元素和其子元素带来的影响)。BFC中只有块级水平的盒子参与(block-level box:display 属性为 block, list-item, table 的元素,会生成 block-level box)

BFC布局规则

l   内部的Box会在垂直方向,一个接一个地放置。

l   Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠

l   每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如 此。

l   BFC的区域不会与float box重叠。

l   BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。

l   计算BFC的高度时,浮动元素也参与计算。

如何触发或建立一个BFC?

  W3C中定义: 浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的BFC(这时这个元素中的内容就同处在一个BFC中)。

当给某一元素添加以下样式中的任意一个时,就触发了BFC。

l   float: left/right/inherit  也就是除none以外的浮动元素

l   position: absolute/fixed 绝对定位元素,fixed是absolute的一个子类,也属于绝对定位

l   display: inline-block、table-cell、table-captions 需要注意的是display: table本身不可以触发BFC,但是由于table会产生匿名盒,而匿名盒的display: table-cell特性会触发BFC,产生新的格式化上下文。(匿名盒:CSS引擎自动生成的盒子,没有名字,不能被 CSS 选择符选中,不能被 CSS 选择符选中意味着不能用样式表添加样式。这意味着所有继承的 CSS 属性值为 inherit ,所有非继承的 CSS 属性值为 initial

l   overflow: hidden/auto/scroll/inherit

了解了以上概念后,我们再来看margin

margin的用途

margin的基本用途就是控制元素与周围其他元素的间隔。

margin的用法

margin通过使用单独的属性,可以对上、右、下、左的外边距进行设置。即:margin-top、margin-right、margin-bottom、margin-left;也可以使用简写的外边距属性同时改变所有的外边距:margin: top right bottom left;

margin的取值

margin的值类型有:auto | length | percentage,

1、如果设置为auto,取值如下

常规流中的块级元素的margin设置为auto时,则margin-left、margin-right的值相等。这个可以用来居中一个块级元素

浮动的元素的margin值为auto时,它的margin-left、margin-right的取值为0

绝对定位的元素的margin值设置为auto时:如果这个元素的left、right、width都是auto,那么它的margin-left、margin-right的值为0;如果这个元素的left、right、width值不是auto,那么margin-right、margin-left的值相等;如果只有一个'margin-left'或者'margin-right'有一个是'auto',则根据公式可计算出另外一个margin的值。;除以上这几种情况外,margin-left和margin-right取值为0

W3C规范中提到的margin为auto时的取值规范

css2.1规范中提到的以下元素margin设置为auto'的水平方向的'margin-left'或者'margin-right'对应的值为'0'

l   内联的不可替换元素(non-replaced inline element):既是内联元素,又是不可替换元素,如 span, strong, i, b, em、cite

l   内联的可替换元素:如:a

l   浮动的不可替换元素(block元素和inline元素)

l   浮动的可替换元素(block元素和inline元素)

l   常规流中的不可替换的inline-block元素

l   常规流中可替换的inline-block元素

常规流中的块级不可替换元素、常规流中的块级可替换元素, 若 margin-left'和'margin-right'都是'auto',那么它们的应用值相等,(这会让该元素相对于其包含块的边水平居中)。

绝对定位的不可替换元素和绝对定位的可替换元素,取值根据一个公式得出

'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = 包含块的宽度。

l   如果'left','width'和'right'全都是'auto':则'margin-left'和'margin-right'的值为0

l   如果'left','width'和'right'都不是'auto':如果'margin-left'和'margin-right'都是'auto,则他们的应用值相等(根据这个规则可以使绝对定位的元素水平居中)

l   如果'margin-left'或者'margin-right'有一个是'auto',则根据上述公式求出另外一个margin的值

l   除以上规则外,'margin-left'和'margin-right'值为0。

2、设置为length的话很好理解,就是实际设置的值,单位可以是px、em等长度值。另外margin值可以设置为负值。

3、percentage:百分比是由被应用 box 的包含块containing block的大小所决定。对于 margin-top 和 margin-bottom 也同样成立。

margin外边距重叠

外边距重叠指的是,当两个垂直外边距相遇时(有可能是同辈或者后辈),它们将形成一个外边距。重叠后的外边距的高度计算如下:

两个相邻的外边距都是正数时,重叠结果是它们两者之间较大的值

两个相邻的外边距都是负数时,重叠结果是两者绝对值的较大值

两个外边距一正一负时,重叠结果是两者的相加的和。

W3C中提到的边距重叠必要条件:

1、必须是常规文档流(不是float和绝对定位,注意绝对定位包含absolute和fixed)中的块级盒子,并且处于同一个BFC当中;

2、没有行盒-即linebox(行盒由一行中所有的内联元素所组成), 没有padding和border将他们隔开;

3、都属于垂直方向上相邻的外边距 。      

W3C中提到的边距重叠的几种情况:

1)       常规文档流中,一个盒子如果没有上补白(padding-top)和上边框(border-top),那么这个盒子的上边距会和其内部文档流中的第一个子元素的上边距合并,这个子元素不能包含间隙(clearance:样式中有clear:right|left|both)。

2)       常规文档流中,一个盒子如果没有下补白(padding-top)和下边框(border-top),那么这个盒子下边距会跟他的下一个兄弟盒子的的上边距合并,除非他们之间存在间隙(clearance)。

3)       常规文档流中,height为auto的盒子的下边距会与它的最后一个子元素的下边距合并;

4)      常规文档流中,一个盒子的高度为0并且最小高度也为0,且不包含常规文档流的子元素,并且自身没有建立新的BFC的,那么它自身的上边距和下边距会合并。

根据上面的条件,不发生外边距重叠的情况有以下几种:

1)       水平方向上永远不会发生外边距合并    

2)       垂直方向上,创建了新的BFC的元素与它的子元素的外边距不会重叠(注意区别:BFC内部的子元素与子元素之间边距是会发生折叠)

3)       一个浮动的元素不与任何元素的外边距产生重叠,包括其父元素及子元素及兄弟元素;(分析:浮动元素脱离了常规文档流,且建立了BFC,他不会影响周围其他元素、也不会被其他元素影响)

4)        overflow设置为hidden|scroll|auto的元素不会与它的子元素的外边距重叠;(分析:overflow不是visible的元素建立了BFC,他不会影响周围其他元素、也不会被其他元素影响)

5)       绝对定位的元素不与任何元素的外边距产生重叠(包括其父元素及子元素及兄弟元素)(分析,脱离了常规文档流,且建立了BFC,他不会影响周围其他元素、也不会被其他元素影响)

6)       行内块级(inline-block)元素不与任何元素的外边距产生重叠(包括其父元素及子元素及兄弟元素)(分析:行内块级元素不符合发生边距重叠的第一个必要条件‘块级盒子’,块级盒子的display属性必须是以下三种之一:'block', 'list-item', 和 'table')

外边距重叠产生的影响

盒子的显示大小= border +content+padding+正margin 值。负的 margin 值不会影响 box 的实际大小,但是负的 top 或 left 值会引起 box 的向上或向左位置移动,如果是 bottom 或 right 只会影响下面 box 的显示的参考线。

     下面是给div元素设置margin:-10px 20px -30px 40px的例子;(借鉴别人的例子)

css中margin重叠和一些相关概念(包含块containing block、块级格式化上下文BFC、不可替换元素 non-replaced element、匿名盒Anonymous boxes )

 如果还不清楚,可以参考网上几篇有关margin的文章

1、 你是否彻底了解margin属性

                                                                                       

2由浅入深漫谈margin属性  

                                                                                       

3关于margin的一些问题 

                                                                                       

4深入理解BFC和Margin Collapse

另外一篇文章介绍了负margin的几个用途,我知道你不知道的负margin

什么时候用margin,什么时候用padding

  何时应当使用margin:需要在border外侧添加空白时。空白处不需要背景(色)时。上下相连的两个盒子之间的空白,需要相互抵消时。如15px + 20px的margin,将得到20px的空白。

  何时应当时用padding:需要在border内测添加空白时。空白处需要背景(色)时。上下相连的两个盒子之间的空白,希望等于两者之和时。如15px + 20px的padding,将得到35px的空白。