Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

块级元素 #9

Open
zhaozy93 opened this issue Jun 27, 2017 · 0 comments
Open

块级元素 #9

zhaozy93 opened this issue Jun 27, 2017 · 0 comments

Comments

@zhaozy93
Copy link
Owner

zhaozy93 commented Jun 27, 2017

块级元素

块级元素也是现在web定位的主要依赖,最基本就是div + css了。对它再熟悉不过。 块级元素一个最大的特征就是它要独占一行,不管内容够不够,反正就是任性。 我们一点点来看块级元素的一些规则。

包含块

每个块级元素在横轴上都有margin-left、border-left、padding-left、width、padding-right、border-right、margin-right这个几个部分构成。一般width指内容区域。
而每个html元素都是由一个外层元素包裹的、我们真正页面上的最外层也至少被body包裹,body也是一个巨大的块级元素。
外层包裹的那个元素其实就是内部元素的“布局上下文”,外层包裹元素就是内层元素的包含块。可能有点抽象

<div class=“wrapper”>
	<div class=“inner”>
		<p></p>
	</div>
</div>

在这个例子中,wrapper就是inner的包含块, inner就是p的包含块。
一般而言,元素都要在它的包含块内进行定位、显示、布局的。当然行内元素不考虑包含块。

水平—块级元素

我们知道一个块级元素 我们可以为其设置宽度,也可以不为其设置宽度。当不为其设置宽度时,它会自动铺满整行。其实这是有根据的:块级元素的宽度之和必须等于包含块的内容区域宽度(规则1,之后会提到) , 而块级元素的宽度之和是指块级元素内容区、左右内边距、左右边框和左右外边距的宽度之和
正是有这个规定,所以我们平时才可以使用margin: 0 auto来实现水平居中。也就是说有在我们普通计算margin-left、border-left、padding-left、width、padding-right、border-right、margin-right 之和不能达到包含块的内容区域宽度时,肯定有属性被浏览器默认更改了。
我们先来看一下各个值初始的默认情况:

margin: 0,  // 取值 具体值、百分比、auto
width: auto,  // 取值 具体值、百分比、auto 等
padding: 0  // 取值 具体值、百分比

我们来一点点测试。
html:

<div style=“width: 1000px; background: red”>
	<div class=“inner” style=“background: yellow”>1</div>
</div>

测试1

不附加任何css规则也就是全部都是默认值,结果发现黄色填满整行。
结论:在margin为0时(默认不进行设置),为满足刚才说的规则1, width会自动延展。
image1

测试2

只设置margin-left或者margin-right, 可以发现结果还是width进行延展。
结论:在只设置一个margin时,为满足刚才说的规则1, width会自动延展。

测试3

设置margin-left和margin-right, 可以发现结果还是width进行延展。
结论:在设置margin-left和margin-right,为满足刚才说的规则1, width会自动延展。
image1

测试4

只设置width时, 可以发现黄色部分尺寸固定,延展的是嘛margin-right。其实这个也可以理解,浏览器是从上到下,从左到右布局,不设置margin-left肯定是不太想有左边间隙,那扩展margin-right也无可厚非
结论:在仅设置width情况下,延展的是margin-right。
image1

测试5

设置width和margin-left时, 可以发现黄色部分尺寸固定,延展的是嘛margin-right。
结论:与测试4的结论一致。

测试6

设置width和margin-right时, 可以发现黄色部分尺寸固定,延展的还是margin-right。
这里比较奇怪,明明设置的margin-right,但是和没设置一样的,那是因为margin-left也有默认值0哦,所以可能没效果,或者认为left优先级比right高吧,至少在从左向右排列格式时。
结论:与测试4的结论一致。

测试7

设置width和margin-right时,同时设置margin-left:auto, 可以发现黄色部分尺寸固定,延展的还是margin-left。
这一次我们发现终于按照我们设想的margin-right体现出来了。
结论:在主动更改margin-left为auto后,width和margin-right会按原设置宽度。
image1

测试8

设置margin-left和width为auto,margin-right为初始值即0。结果与不进行任何设置一样。
结论:margin的auto优先级低于width的auto。
image1

测试9

设置margin-left、margin-right、 width全部为auto。结果与测试8测试1一样。
结论:与测试8的结论一致。

结论

  • 可以粗略的认为为了满足规则1, width、margin-left、margin-right一定会有一个值变为auto
  • width默认初始值就是auto,因此在不进行margin设置时,width会延展,同时width的auto会优先于margin的auto。
  • 有width值时,margin的auto才会起作用,但margin的默认值时0哦,因此不进行margin设置时,margin-right会被延展。只有在margin-left设置为auto时,margin-left才有可能被延展。

负margin

水平上负margin导致width总和可能会超出包含块内容区域。
一般为扩展宽度采用。

垂直—块级元素

在垂直方向上,其实一般不太关心,毕竟浏览器下滑已经是大家都习以为常的事情。 因此很多时候我们不会为块级元素设置高度。
默认情况下height: auto, 因此他会随着内部元素增加而自动拉伸,但如果显式的设置它的高度,他就不会再拉伸了。

为垂直方向设置margin: auto 0,其实是没有意义的,它会将margin-top和margin-bottom重置为0, 其实它就失去了上下外边距。当然定位和浮动元素不算。

外边距合并

在垂直外边距合并指的是,**当两个垂直外边距相遇时,它们将形成一个外边距。合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。**但只有普通文档流中块框的垂直外边距才会发生外边距合并。行内框、浮动框或绝对定位之间的外边距不会合并。
下面是w3c官方的解释 为什么会出现垂直外边距折叠。

Two margins are adjoining if and only if:
• both belong to in-flow block-level boxes that participate in the same block formatting context
• no line boxes, no clearance, no padding and no border separate them (Note that certain zero-height line boxes (see 9.4.2) are ignored for this purpose.)
• both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
◦ top margin of a box and top margin of its first in-flow child
◦ bottom margin of box and top margin of its next in-flow following sibling
◦ bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height
◦ top and bottom margins of a box that does not establish a new block formatting context and that has zero computed 'min-height', zero or 'auto' computed 'height', and no in-flow children
这里面有一个很重要的条件就是两个折叠元素都是普通文档流in-flow,并且没有非空内容、padding、border 或 clear 分隔开, 同时最后几个小例子也说明外边距折叠不一定只发生在相邻兄弟元素,父级与子元素也可以。

按照规定来说我们如果要解决外边距折叠的问题可以有以下几条思路:

  • 不是块级元素 例如inline-block、table-cell、table-caption、inline-block
  • 脱离文档流 例如absolute、fixed、float
  • 在每两个margin之间不管是margin-top和margin-bottom还是margin-top和margin-top之间插入内容、padding或者border都可以。

然后我们在这里都没有发现任何BFC(格式化上下文)的影子, 那为什么经常能看到BFC来解决外边距折叠呢?
先来看如何触发BFC:

float(除了none)、overflow(除了visible)、display(table-cell/table-caption/inline-block)、position(除了static/relative)。
可以看出来解决外边距折叠是触发BFC机制的子集,言外之意是即使触发了BFC依旧可能发生外边距折叠,比如说设置overflow: hidden(仅不会与子元素合并,但依旧可能与相邻元素合并)。

看完上面的内容希望得出一个基本的结论: 外边距折叠是外边距折叠,BFC是BFC,两者还是要进行区别开来的。

  • 外边距合折叠发生时,应该考虑padding、margin是不是都正确搭配使用了,正确的使用可以避免90%以上的外边距合并。(比例是猜的)

总结

块级元素在CSS中其实不关心,CSS关心的是块级盒子,只是块级盒子是由块级元素产生的,这部分内容可以看另一篇BFC的文章。在块级盒子之上其实还有一个BFC的概念,BFC之内才是块级盒子自由的排版。但BFC不是一个特殊的元素,而是块级元素的某些特殊属性产生的。
上文仅仅介绍的是块级元素的一些特性,从水平和垂直两个切入点来理解块级元素的一些特性,也理解了一下外边距折叠的触发条件与解决思路。强烈推荐本文搭配BFC一起浏览。

@zhaozy93 zhaozy93 mentioned this issue May 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant