ホームページ >ウェブフロントエンド >htmlチュートリアル >CSS マジック ホール: ボックス モデル、IFC、BFC およびマージンの崩壊を理解する_html/css_WEB-ITnose
前言盒子模型作为CSS基础中的基础,曾一度以为掌握了IE和W3C标准下的块级盒子模型即可,但近日在学习行级盒子模型时发现原来当初是如此幼稚可笑。本文尝试全面叙述块级、行级盒子模型的特性。作为近日学习的记录。
何为盒子模型?盒子模型到底何方神圣居然可以作为CSS的基础?闻名不如见面,上图了喂!再来张切面图吧!下面我们以 dc6dce4a544fdca2df29d5ac0ea9906b16b28748ea4df4d9c2150843fecfba68 为栗子。 dc6dce4a544fdca2df29d5ac0ea9906b16b28748ea4df4d9c2150843fecfba68 タグがブラウザによって解析されると、div 要素が生成され、ドキュメント ツリーに追加されます。ただし、CSS が作用するオブジェクトはドキュメント ツリーではなく、ドキュメント ツリーに基づいて生成されたレンダー ツリーです。ボックス モデルはレンダー ツリーのノードです。 * 注意:* 1. CSS は要素ではなくボックスに対して機能します。* 2. JS はボックスを直接操作できません。
ボックスモデルの構造ブロックレベルのボックスは効果を検証する際に干渉する情報が少ないため、ボックスモデルを理解しやすいため、ブロックレベルのボックスモデルは次のようになります。以下で説明します。 注: 行レベルのボックス モデルはブロック レベルのボックス モデルと同じ構造を持っていますが、行レベル ボックスにはこれに基づいた独自の特性があります。 上の 2 つの図は、ボックス モデルが実際に次の 4 つのボックスで構成されていることを示しています。 1. コンテンツ ボックス: 必須、コンテンツ領域と 4 つのコンテンツ/内側のエッジで構成されます。 2. パディング ボックス: オプションで、パディングで構成されます。 4 つのパディング エッジで構成されます。パディング幅が 0 に設定されている場合、パディング エッジはコンテンツのエッジにオーバーラップします。 3. 境界ボックス: オプション。境界と 4 つの境界エッジで構成されます。境界線の幅が 0 に設定されている場合、境界線のエッジはパディングのエッジとオーバーラップします。 4. マージン ボックス: オプションで、マージンと 4 つのマージン/外側のエッジで構成されます。マージン幅を 0 に設定すると、マージン エッジが境界エッジと重なります。 CSS を初めて使用する学生は、「width/height 属性を使用して div 要素の幅/高さを設定する」と考えがちですが、実際にはこの文は間違っています。 1. まず、CSS 属性の幅と高さは、要素自体ではなく、div 要素によって生成されるボックスに作用します。 2. さらに、ボックス モデルは 4 つのボックスで構成されます。どのボックスが幅と高さに作用するのでしょうか。ここではIEボックスモデルとスタンダードボックスモデルに分かれています。 IE ボックス モデル IE5.5 (変なモード) は IE ボックス モデルを採用し、その他は W3C 標準ボックス モデルを使用します。
width = content-width + padding-width + border-widthheight = content-height + padding-height + border-height
標準ボックスモデル
width = content-widthheight = content-height
IE ボックス モデルと標準ボックス モデルの間を行き来する - ボックス サイズ属性幅と高さを分割する方法が 2 つあることがわかりましたが、どちらが正しいでしょうか?実際、どちらも正しいですが、使い方によって異なります。さらに、IE8 は CSS3 属性 box-sizing のサポートを開始し、使用するボックスを自由に選択できるようになります:) box-sizing: content-box/border-box/inheritcontent-box - デフォルト値、標準ボックス modelborder-box を使用します。 - IE ボックスのモデル継承の使用 - 親要素の属性値の継承サンプル:
Element{ -moz-box-sizing: border-box; // FireFox3.5+ -o-box-sizing: border-box; // Opera9.6(Presto内核) -webkit-box-sizing: border-box; // Safari3.2+ -ms-box-sizing: border-box; // IE8 box-sizing: border-box; // IE9+,Chrome10.0+,Safari5.1+,Opera10.6}
行レベルのボックス - 疑わしい人生の出発点: ) 以前に理解したボックスモデルは上記のとおりでした。行レベルのボックスのさまざまな現象を見て、私は人生を疑い始めました:(幅/高さが機能しません...
.defined-wh{ width: 100px; height: 50px; border: solid 1px red; background: yellow;}ブロックレベルボックスの場合
<div class="defined-wh"></div>インラインレベルボックスの場合
<span class="defined-wh"></span>行レベルのボックスの幅が 0 であるのに、高さが 50 ピクセルではないのはなぜですか?単純です。つまり、レベル ボックスのコンテンツ ボックスの高さ/幅は高さ/幅によってまったく設定されません。コンテンツ ボックス/領域の高さは、コンテンツ ボックス/領域の幅によって決まります。子の行レベル ボックスの外側の幅 (マージン) に等しい) >
ブロック レベル ボックスの場合
インラインレベルのボックスの場合
.broken{ border: solid 1px red; background: yellow;}
行レベルのボックスが分割されていて可哀想さらに残念なのは、双方向コンテキストのインライン要素のボックス モデルが、W3C 勧告で説明されている、最も左に生成されるボックスである 'ltr' です。要素が表示される最初の行ボックスには左マージン、左ボーダー、左パディングがあり、要素が表示される最後の行ボックスの右端に生成されたボックスには右パディング、右ボーダー、右マージンがあります。要素の 'direction' プロパティが 'rtl' の場合、要素が表示される最初の行ボックスの右端に生成されたボックスには右パディング、右ボーダー、右マージンが設定され、最終行の左端に生成されたボックスには右のパディング、右ボーダー、右マージンが設定されます。要素が表示されるボックスには左マージン、左ボーダー、左パディングがあります。つまり、インラインレベルのボックスの幅が親コンテナの幅より大きい場合、ボックスは複数のインラインボックスに分割されます。レベルボックス、属性の方向が ltr の場合、margin/border/padding-left は最初のインラインレベルのボックスに作用し、属性の方向が ltr の場合は margin/border/padding-right が最後のインラインレベルのボックスに作用します。 rtl、margin/border/padding-right は最初のインライン レベル ボックスに作用し、margin/border/padding-left は最後のインライン レベル ボックスに作用します。それを見ましたか?行レベルのボックスは本当に細かく切り刻まれてしまうので、とても残酷です:|
<div class="broken">一段文字一段文字一段文字一段文字一段文字一段文字</div>
行级盒子怎么不占空间了?怎么刷存在感啊。。。
.existed{ margin: 20px; padding: 20px; border: solid 1px red; background: yellow; background-clip: content-box;}
对于block-level box
<div>before bababababababa</div><div class="existed">babababababababababa</div><div>after bababababababa</div>
对于inline-level box
<div>before bababababababa</div><span class="existed">babababababababababa</span><div>after bababababababa</div>
看,行级盒子的margin/border/padding-top/bottom怎么均不占空间的?难道行级盒子仅有content box占空间吗?这里已经涉及到水平和垂直方向排版的范畴了,仅以盒子模型已无法解析理解上述的问题。(要结合https://www.w3.org/TR/CSS2/box.html和https://www.w3.org/TR/CSS21/visuren.html、https://www.w3.org/TR/CSS21/visudet.html来理解了!)
在深入解释inline-level box的上述现象前,我们需要补充一下:1. 一个元素会对应0~N个box;(当设置display:none;时,则对应0个box)2. 根据display属性值,元素会对应不同类型的controlling box(inline/block-level box均是controlling box的子类). 就CSS2而言display:inline|inline-block|inline-table|table-cell|table-column-group的元素对应inline-level box,而display:block|list-item|table|table-caption|table-header-group|table-row|table-row-group|table-footer-group的元素则对应block-level box;3. box布局/排版时涉及到定位问题,而CSS中通过positioning scheme来定义,其包含normal flow、floats和absolute positioning三种定位方式.而normal flow包含block formatting、inline formatting和relative positioning,其中BFC为block formatting的上下文,IFC为inline formatting的上下文。
因此大家请注意,前方高能,前方高能!!!
和IFC一起看inline-level boxIFC(Inline Formatting Context),直译为“行内格式化上下文”,这是什么鬼的翻译啊?反正我对于名词一向采用拿来主义,理解名词背后的含义才是硬道理。我们简单理解为每个盒子都有一个FC特性,不同的FC值代表一组盒子不同的排列方式。有的FC值表示盒子从上到下垂直排列,有的FC值表示盒子从左到右水平排列等等。而IFC则是表示盒子从左到右的水平排列方式,仅此而已(注意:一个盒子仅且仅有一个FC值)。而inline-level box的FC特性值固定为IFC。另外仅处于in-flow的盒子才具有FC特性,也就是positioning scheme必须为Normal flow的盒子才具有FC特性。除了IFC外,对于inline-level box排版而言还有另一个重要的对象,那就是line box。line box是一个看不见摸不着的边框,但每一行所占的垂直高度其实是指line box的高度,而不是inline-level box的高度。 line box的特点:1. 同一行inline-level box均属于同一个line box;2. line box高度的计算方式(https://www.w3.org/TR/CSS21/visudet.html#line-height)>The height of each inline-level box in the line box is calculated. For replaced elements, inline-block elements, and inline-table elements, this is the height of their margin box; for inline boxes, this is their ‘line-height’.>The inline-level boxes are aligned vertically according to their ‘vertical-align’ property. In case they are aligned ‘top’ or ‘bottom’, they must be aligned so as to minimize the line box height. If such boxes are tall enough, there are multiple solutions and CSS 2.1 does not define the position of the line box’s baseline.>The line box height is the distance between the uppermost box top and the lowermost box bottom.
.parent{ line-height: 1; font-size: 14px; border: solid 1px yellow;}.child{ font-size: 30px; vertical-align: middle; border: solid 1px blue;}.inline-block{ display: inline-block; overflow: hidden; border: solid 1px red;}.other{ border: solid 1px green;}
<span class="parent"> <span class="child"> <span class="inline-block">display:inline-block元素</span> xp子元素的文字 </span> xp父元素的文字</span><div class="other">其他元素</div>
1. 根据规则,span.parent所在行的line box的高度受span.parent、span.child、span.inline-block元素对应的inline-level box”高度”的影响。其中span.parent的”高度”为其line-height实际值,span.child的”高度”为其line-height实际值,而span.inline-block的”高度”为其margin box的高度。由于设置line-height:1,因此span.parent和span.child的content box高度等于line-height实际值;2. 根据vertical-align属性垂直对齐,造成各“高度”间并不以上边界或下边界对齐;3. span.inline-block红色的上边框(border top)到span.child蓝色的下边框(border bottom)的距离再减去1px即为line box的高度。(line box的下界其实是span.child的content box的下限的,你看”其他元素”的上边框不是和span.child的下边框重叠了吗?如果那是line box的下界,那怎会出现重叠呢)
这里又涉及到另一个属性vertical-align了,由于它十分复杂,还是另开文章来叙述吧!
行级盒子小结 **就盒子模型而言**1. inline-level box与block-level box结构一致;2. content box的高度仅能通过属性font-size来设置,content box的宽度则自适应其内容而无法通过属性width设置;3. 当inline-level box的宽度大于containing block,且达到内容换行条件时,会将inline-level拆散为多个inline-level box并分布到多行中,然后当属性direction为ltr时,margin/border/padding-left将作用于第一个的inline-level box,margin/border/padding-right将作用于最后一个的inline-level box;若属性direction为rtl时,margin/border/padding-right将作用于第一个的inline-level box,margin/border/padding-left将作用于最后一个的inline-level box。
**垂直排版特性**inline-level box排版单位不是其本身,而是line box。重点在于line box高度的计算。1. 位于该行上的所有in-flow的inline-level box均参与该行line box高度的计算;(注意:是所有inline-level box,而不仅仅是子元素所生成的inline-level box)2. replaced elements, inline-block elements, and inline-table elements将以其对应的opaque inline-level box的margin box高度参与line box高度的计算。而其他inline-level box则以line-height的实际值参与line box高度的计算;3. 各inline-level box根据vertical-align属性值相对各自的父容器作垂直方向对齐;4. 最上方的box的上边界到最下方的下边界则是line box的高度。(表述不够清晰,请参考实例理解)
Collapsing margins 大家必定听过或遇过collapsing margins吧,它是in-flow的block-level box排版时的一类现象。说到排版那必须引入另一个FC特性值——BFC(Block Formatting Context)的。BFC则是表示盒子从上到下的垂直排列方式,仅此而已(注意:一个盒子仅且仅有一个FC值)。而block-level box的FC特性值固定为BFC。collapsing margins规则 1. 元素自身margin-top/bottom collapsing
anonymous block-level box<div class="margins"></div>anonymous block-level box<div class="margins border"></div>anonymous block-level box
.margins{margin: 50px 0 70px;}.border{border: solid 1px red;}
当block-level box高度为0,垂直方向的border和padding为0,并且没有in-flow的子元素。那么它垂直方向的margin将会发生重叠。
2. 父子元素margin-top/top 或 margin-bottom/bottom collapsing
anonymous block-level box<div class="parent-margins"> <div class="margins border"></div> anonymous block-level box <div class="margins border"></div></div>anonymous block-level box<div class="parent-margins border"> <div class="margins border"></div> anonymous block-level box <div class="margins border"></div></div>anonymous block-level box
.parent-margins{margin: 25px 0;}.margins{margin: 50px 0 25px;}.border{border: solid 1px red;}
当父子元素margin-top间或margin-bottom间没有padding、border阻隔时,则会margin会发生重叠。注意空白字符会造成目标父子元素间的存在anonymous block-level box,导致margin不重叠。
anonymous block-level box<div class="parent-margins"> <div class="margins border"></div> anonymous block-level box <div class="margins border"></div></div>anonymous block-level box
3. 兄弟元素margin-bottom/top collapsing
<div class="margins">former</div><div class="margins">latter</div>
.margins{margin: 50px 0 25px;}
两个相邻的in-flow block-level box的上下margin将发生重叠。
**上述为默认情况下block-level box(即display:block,其它为默认值时)的margin重叠规则**那非默认情况下呢?相比非默认情况下的margin重叠规则,我们更关心是什么时候不会产生重叠。这时又引入了另一个概念——生成新BFC。也就是block-level box A与block-level box B的FC特性值BFC可能是不同的。当两个相邻box的FC值不为同一个BFC时,它们的margin绝对不会重叠。那么剩下的问题就是,到底何时会产生新的BFC?哪些block-level box会采用新的BFC?默认BFC又是谁生成的呢?其实根元素(html)会生成默认BFC供其子孙block-level box使用。采用floats或absolute positioning作为positioning scheme时,或display:inline-block/table-cell/table-caption/flex/inline-flex或overflow属性值不为visible时,则会产生新的BFC;而新的BFC将作为子孙block-level box的FC属性值。 注意: 1. 产生新BFC的盒子不会与子盒子发生margin重叠; 2. display:inline-block的盒子不与 兄弟 和 父 盒子发生margin重叠,是因为display:inline-block的盒子的FC特性值为IFC,还记得line box吗?没有margin重叠是自然不过的事了; 3. positioning scheme为floats的盒子不与floated的兄弟盒子发生margin重叠,也不会与前一个in-flow的兄弟盒子发生margin重叠。(注意:与父盒子也不会发生margin重叠)
<div class="margins border">sibling</div><div class="margins border float">floats1</div><div class="margins border float">floats2</div>
.margins{margin: 50px 0 50px;}.border{border: solid 1px red;}.float{float:left;width:200px;}
归纳FC、BFC和IFC
由于上述主要阐述inline/block-level box,因此通过“仅此而已”来简化BFC和IFC的内涵。下面我们稍微全面一点去理解BFC和IFC如何影响inline/block-level box。
FC(Formatting Context),用于初始化时设置盒子自身尺寸和排版规则。注意“初始化”,暗指positioning scheme采用的是normal flow,要知道floats和absolute positioning均不是默认/初始化值。也就是说我们在讨论FC及BFC和IFC时,均针对in-flow box而言的。 BFC**对于不产生新BFC的盒子**1. block-level boxes垂直排列,盒子的left outer edge与所在的containing block的左边相接触,默认情况下(width为auto时)right outer edge则与所在的containing block的右边相接触。即使存在floated的兄弟盒子。
<div id="container" style="border:solid 2px red;"> <div id="left" style="float:left;width:300px;height:30px;background:yellow;opacity:0.2;"></div> <div id="right" style="height:30px;background:#999;"></div></div>
虽然 div#left 浮点了,但 div#right 的left outer edge还是与 div#container 的left content edge相接触。 div#right 所在的containing block就是 div#container 的content box.2. block-level box高度的计算The element’s height is the distance from its top content edge to the first applicable of the following:the bottom edge of the last line box, if the box establishes a inline formatting context with one or more linesthe bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child’s bottom margin does not collapse with the element’s bottom marginthe bottom border edge of the last in-flow child whose top margin doesn’t collapse with the element’s bottom marginzero, otherwiseOnly children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored, and relatively positioned boxes are considered without their offset).
也就out-flow box不影响block-level box高度的计算。也就是解释了为何div中仅含floated元素时,div盒子高度为0的现象了。
**对于产生新BFC的盒子**对于产生新BFC的盒子而言,除了不发生collapsing margins的情况外,还有两个与浮点相关的现象。1. out-flow box纳入block-level box高度的计算In addition, if the element has any floating descendants whose bottom margin edge is below the element’s bottom content edge, then the height is increased to include those edges. Only floats that participate in this block formatting context are taken into account, e.g., floats inside absolutely positioned descendants or other floats are not.也就positioning scheme为floats的box也会影响block-level box高度的计算。
2. 誓死不与positioning scheme为floats的兄弟盒子重叠The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with ‘overflow’ other than ‘visible’) must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3. CSS2 does not define when a UA may put said element next to the float or by how much said element may become narrower.
产生新BFC的block-level box不与floated-box重叠,而是floated-box的margin-box与block-level box的border-box相接触。水平方向
<div style="float:left;width:100px;border: solid 1px red;margin-right:50px;">floated</div><div style="width:200px;border: solid 1px blue;margin-left:100px;overflow:hidden;">gen new BFC balabala</div>
垂直方向
<div style="float:left;width:100px;border: solid 1px red;margin-bottom:50px;">floated</div><div style="width:200px;border: solid 1px blue;margin-top:100px;overflow:hidden;">gen new BFC balabala</div>
IFC
提起IFC那就不能不说line box,而line box高度的计算方式上面已经叙述了,那line box的宽度呢?line box默认情况下左边框与containing block的左边框接触,右边框与containing block的右边框接触。若存在floated兄弟盒子,则line box的宽度为containing block的宽度减去floated-box的outer-box的宽度。而inline-level box必须包含在line box中,若inline-level box的white-space:nowrap或pre外的其他值时,就会将inline-level box拆分为多个inline-level box并散落到多个line box中,从而实现文字环绕图片的效果了。否则inline-level box会捅破line box(即line box宽度不变)
行——换与不
先看看关于换行的CSS属性吧!
white-space normal: 忽略/合并空白 pre: 保留空白,如同<pre class="brush:php;toolbar:false">的行为 nowrap: 忽略/合并空白,文本不会换行,直到遇到<br/> pre-wrap: 保留空白,但是会正常地进行换行 pre-line: 忽略/合并空白,但是会正常地进行换行 inherit: 从父元素继承。 word-wrap normal: 只在允许的断字点换行 break-word: 在长单词或URL地址内部进行换行 word-break normal:依照亚洲和非亚洲语言的文本规则,允许在单词内换行。 keep-all:让亚洲语言文本如同非亚洲语言文本那样不允许在任意单词内换行。 break-all:允许非亚洲语言文本行如同亚洲语言文本那样可以在任意单词内换行。
具体示例可参考:css中强制换行word-break、word-wrap、white-space区别实例说明
改行を扱う場合、扱わなければならないオブジェクトはアジア言語のテキストと非アジア言語のテキストに分けられます。アジア言語のテキストの場合は単語が操作単位として使用され、非アジア言語のテキストの場合は単語が操作単位として使用されます。改行は特定の言語テキストの操作単位で処理されるため、デフォルトでは、スペースが自動的に折り返されない「中国語」の文字列が表示されますが、スペースはなく改行も含まれない「英語」の文字列が表示されます。私たち (アジア人) は通常、中国語と英語で自動行折り返し効果を実現するために word-break:break-all;word-wrap:break-word; を使用しますが、英語の単語自体をそのような単純な方法で折り返すことはできません。粗雑なやり方。英単語の遷移には一定のルールがあり、それを要約すると次のとおりです。ハイフン「-」は遷移部分で使用し、印刷記号のスペースのみを占め、行の最後に配置します。通常、トランジションは音節に基づいているため、2 つの音節の間でのみ区切ることができ、完全な音節を上の行と下の行に記述することはできません。たとえば、Octob-ber (正)、Octob-er (誤り) です。 。複合語は、単語を構成する 2 つの部分の間を移動する必要があります。例: some-thing、bed-room など。複合語にもともとハイフンが含まれている場合は、元のハイフンの位置で改行します。 例: Good-Looking など。 5. 2 つの異なる子音が一緒にある場合、遷移の前後に 1 つずつ存在します。たとえば、cap-tain、ex-pose などです。 2 つの音節の間に子音文字が 1 つしかない場合、子音文字の前の母音文字が強勢開音節の規則に従って発音されると、子音文字は次の行に移動します。たとえば、「fa-ther」などです。母音文字は強調閉音節ルールに従って発音されます。音節が規則的に発音される場合、子音文字は前の行の末尾に残ります。例: man-age など。二重に書かれた子音がある場合、通常は前後に 1 つずつ分けられます。例: mat-ter など。 8.強調された音節が最後に来る場合、通常、母音文字の前の子音文字は次の行に移動されます。例: po-lite など。単音節の単語は移動できません。例: 長さ、長い、ダンスなど。 10.プレフィックスまたはサフィックスはそのままにしておく必要があり、個別に記述することはできません。たとえば、unfit、disease などです。 11.アラビア数字は行を分けて記載しません。12.音節の数に関係なく、固有名詞は別々に書かないでください。例: ナンシー、ロシアなど。 13.特定の単語の略語、省略形、または短縮形を行に記述することはできません。たとえば、「U」です。 N. (国連)、P. R. C. (中華人民共和国)ではありません。14.音節を形成できない語尾は分けて書かれません。例:停止など。 15.文字の組み合わせや子音の連結は移動できません。例: machine、meat など。
CSS は、改行が複合語である場合は、元のハイフン記号で改行します。 、単語全体 次の行に移動します。したがって、word-wrap:break-word; を使用しても問題ありません。
さらに、word-break:keep-all;white-space:nowrap; を使用して改行なしの効果を実現することもできます。概要 最後に、ボックス モデル、BFC および IFC大まかな説明。 BFC の場合、重要なポイントはマージンの縮小と新しい BFC の生成の動作です (これにはフローティングなどの交差があります。これについては後で説明します)。実際、IFC はライン ボックスの理解に重点を置いています。ブロックレベルのボックスは垂直方向に配置されますが、インラインレベルのボックスはラインボックスをコンテナとして使用して水平方向の配置を実現します。この時点で、IFC を理解するのは BFC よりもはるかに難しいことがわかりますが、この記事の基礎があれば、後で text-align、line-height、vertical-align を理解するのがはるかに簡単になります。
この記事はあくまで私の個人的な理解ですので、間違いがあればご指摘ください。
ありがとう
http://div.io/topic/834?page=1#3261(BFC)
http://www .cnblogs.com/giggle/p/5236982.html(BFC)
https://segmentfault.com/a/1190000003043991 (IFC)
http://www.cnblogs.com /Winter-cn/archive/2013/05/11/3072929.html (BFC/IFC)
[KB010: 通常のフロー (通常のフロー)](http://www.w3help.org/zh- cn/kb/010/)[CSS 101: ブロックの書式設定コンテキスト](http://yuiblog.com/blog/2010/05/19/css-101-block-formatting-contexts/)
フロントエンドスタックエンジニアの個人ホームページ · 私の記事 · 1 ·