理解 CSS 布局和 BFC

CSS布局中有一些概念,一旦你理解了它们,就能真正提高你的 CSS 布局能力。本文是关于块格式化上下文(BFC)的。你可能从未听说过这个术语,但是如果你曾经用CSS做过布局,你可能知道它是什么,理解什么是 BFC,怎么工作以及如何创建 BFC 非常有用,这些可以帮助你理解CSS中的布局是如何工作的。在本文中,通过熟悉的示例来解释什么是 BFC。然后说明 display 的一个新值,只有当你理解了什么是 BFC 以及为什么需要它时,它才有意义。什么是 BFC在一个Web页面的CSS渲染中,块级格式化上下文 (Block Fromatting Context)是按照块级盒子布局的。W3C对BFC的定义如下:浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的BFC(块级格式上下文)。BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个 BFC 中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。块格式化上下文(BFC)的行为通过一个简单的float示例很容易理解。在下面的示例中,我有一个框,其中包含向左浮动的图像和一些文本。如果我们有足够多的文本,它会环绕浮动的图像和边框,然后环绕整个区域。// html<div class=“outer”> <div class=“float”>I am a floated element.</div> I am text inside the outer box.</div>// css.outer { border: 5px dotted rgb(214,129,137); border-radius: 5px; width: 450px; padding: 10px; margin-bottom: 40px;}.float { padding: 10px; border: 5px solid rgba(214,129,137,.4); border-radius: 5px; background-color: rgba(233,78,119,.4); color: #fff; float: left; width: 200px; margin: 0 20px 0 0;}如果我删除了一些文本,那么就没有足够的内容来包围图像,而且由于浮动被从文档流中脱离,所以边框会上升,并在图像下方,直到文本的高度。这是因为当我们浮动一个元素时,文本所在的框的宽度保持不变,为给浮动元素腾出空间而缩短的是文本的行框。这就是为什么背景和边框会出现在浮动后面的原因。我们通常有两种方法来解决这个布局问题。一种方法是使用 clearfix hack,它的作用是在文本和图像下面插入一个元素,并将其设置为 clear:both。另一种方法是使用 overflow 属性,其值不是缺省值 visible。.outer { overflow: auto;}查看演示overflow 以这种方式工作的原因是,使用 visible 的初值以外的任何值都会创建一个块格式化上下文,而 BFC 的一个特性是它包含浮动。BFC 是布局中的一个迷你布局你可以将 BFC 看作是页面内的一个迷你布局。一旦一个元素创建了一个 BFC,它就包含了所有的内容。正如我们所看到的,这包括浮动的元素,它们不再从盒子底部伸出来。BFC 还会导致一些其他有用的行为。BFC 可以防止 margin 折叠了解边距合并是另一个被低估的 CSS 技能。在下一个示例中,假设有一个背景颜色为灰色的 div。这个 div 包含两个标签 p。外部 div 元素的 margin-bottom 为 40 像素,标签 p 的顶部和底部 margin 都是 20 像素。// html<div class=“outer”> <p>I am paragraph one and I have a margin top and bottom of 20px;</p> <p>I am paragraph one and I have a margin top and bottom of 20px;</p></div> // css.outer { background-color: #ccc; margin: 0 0 40px 0;}p { padding: 0; margin: 20px 0 20px 0; background-color: rgb(233,78,119); color: #fff;}因为 p 元素的 margin 和外部 div 上的 margin 之间没有任何东西,所以两个会折叠,因此 p 最终与 div 的顶部和底部齐平。 我们在 p 的上方和下方看不到任何灰色。在CSS当中,相邻的两个盒子(可能是兄弟关系也可能是祖先关系)的外边距可以结合成一个单独的外边距。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。折叠的结果按照如下规则计算:两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。两个外边距一正一负时,折叠结果是两者的相加的和。产生折叠的必备条件:margin必须是邻接的!如果我们把盒子设为 BFC,它现在包含了标签 p 和它们的边距,这样它们就不会折叠,我们可以看到边距后面容器的灰色背景。.outer { background-color: #ccc; margin: 0 0 40px 0; overflow: auto;}查看演示再一次,BFC 的工作是把东西装在盒子里,防止它们从盒子里跑出来。 BFC 可以阻止元素被浮动元素覆盖你将熟悉 BFC 的这种行为,因为使用浮动的任何列类型布局都是这样工作的。如果一个项目创建了一个 BFC,那么该项目将不会包裹任何浮动元素。在下面的例子中,有如下 html 结构:<div class=“outer”> <div class=“float”>I am a floated element.</div> <div class=“text”>I am text</div></div>带有 float 类的项被向左浮动,因此 div 中的文本在它环绕 float 之后。我可以通过将包裹文本的 div 设置为 BFC 来防止这种包裹行为。.text { overflow: auto;}这实际上是我们创建具有多个列的浮动布局的方法。浮动项还为该项创建了一个 BFC,因此,如果右边的列比左边的列高,那么我们的列就不会相互环绕。查看演示在多列布局中使用 BFC如果我们创建一个占满整个容器宽度的多列布局,在某些浏览器中最后一列有时候会掉到下一行。这可能是因为浏览器四舍五入了列宽从而所有列的总宽度会超出容器。但如果我们在多列布局中的最后一列里创建一个新的BFC,它将总是占据其他列先占位完毕后剩下的空间。例如:<div class=“container”> <div class=“column”>column 1</div> <div class=“column”>column 2</div> <div class=“column”>column 3</div></div>对应的CSS:.column { width: 31.33%; background-color: green; float: left; margin: 0 1%;}.column:last-child { float: none;}未创建 BFC 之前:添加以下样式创建一个 BFC:.column:last-child { float: none; overflow: hidden; }现在尽管盒子的宽度稍有改变,但布局不会打破。当然,对多列布局来说这不一定是个好办法,但能避免最后一列下掉。这个问题上弹性盒或许是个更好的解决方案,但这个办法可以用来说明元素在这些环境下的行为。还有什么能创建 BFC?除了使用 overflow 创建 BFC 外,其他一些 CSS 属性还创建 BFC。正如我们所看到的,浮动元素创建了 BFC。你的浮动项将包含它里面的任何东西。使用以下方式都能创建 BFCfloat 的值不是 none。position 的值不是 static 或者 relative。display 的值是 inline-block、table-cell、flex、table-caption 或者inline-flexoverflow 的值不是 visible创建 BFC 的新方式使用overflow或其他的方法创建BFC时会有两个问题。首先,这些方法本身是有自身的设计目的,所以在使用它们创建BFC时可能会产生副作用。例如,使用overflow创建BFC后在某些情况下可能会看到出现一个滚动条或者元素内容被裁切。这是由于overflow属性的设计是用来让你告诉浏览器如何定义元素的溢出状态的。浏览器执行了它最基本的定义。即使在没有任何不想要的副作用的情况下,使用 overflow 也可能会让其他开发人员感到困惑。为什么 overflow 设置为 auto 或 scroll?最初的开发者的意图是什么?他们想要这个组件上的滚动条吗?最安全的做法应该是创建一个 BFC 时并不会带来任何副作用,它内部的元素都安全的呆在这个迷你布局中,这种方法不会引起任何意想不到的问题,也可以理解开发者的意图。CSS 工作组也十分认同这种想法,所以他们定制了一个新的属性值:display:flow-root。flow-root 浏览器支持情况你可以使用display:flow-root安全的创建BFC,来解决上文中提到的各种问题:包裹浮动元素、阻止外边距叠加和阻止围绕浮动元素。浏览器对该属性的支持目前还是有限的,如果你觉得这个属性值很方便,请投票去让Edge也支持它。不过无论如何,你现在应该已经理解了什么是 BFC,以及如何使用 overflow 或其他方法来包裹浮动,以及知道了 BFC 可以阻止元素去环绕浮动元素,如果你想使用弹性或网格布局可以在一些不支持他们的浏览器中使用 BFC 的这些特性做降级处理。理解浏览器如何布置网页是非常基础的。 虽然有时看起来无关紧要,但是这些小知识可以加快创建和调试 CSS 布局所需的时间。你的点赞是我持续分享好东西的动力,欢迎点赞!一个笨笨的码农,我的世界只能终身学习!更多内容请关注公众号《大迁世界》! ...

March 27, 2019 · 2 min · jiezi

CSS BFC特性(块级格式化上下文)

1、元素的BFC特性BFC全称为”Block Formartting Context”,中文为”块级格式化上下文”。它是页面中的一块独立的渲染环境,并且有一套渲染规则,它决定了其子元素将如何定位,以及它和其他兄弟元素的关系和相互作用。BFC布局规则:1)bfc内部的元素会在垂直方向,一个接一个地放置2)盒子垂直方向的距离有margin决定,属于同一个bfc的两个相邻元素的margin会发生重叠3)每个盒子的左外边缘(margin-left)会与其父元素的左边缘(border-left)相接触4)bfc的区域会通过变窄来自适应而不会与float元素重叠在一起5)bfc的高度计算时,浮动元素也参与计算。即创建了新的bfc的元素的高度会把内部浮动元素的高度也算进去6)bfc是页面上一个隔离的独立容器,容器内的子元素不会影响到外面的元素;同理容器内的子元素也不会影响到父元素外面的其他元素。创建BFC的条件:a)html元素b)float的值不为nonec)overflow的值为auto、hidden或scrolld)display的值为table-cell、inline-block、table-caption、flex、inline-flexe)position的值不为relative和static2、BFC作用—-理解BFC(个人理解)1、因为bfc内部的元素与外部的元素绝对不会互相影响,因此当bfc元素的兄弟元素有浮动时,它不应该影响bfc内部元素的布局,所以bfc会通过变窄来自适应,而不会与浮动元素发生重叠;2、同样的,当bfc内部有浮动时,为了不影响外部元素的布局,bfc计算高度时会把浮动元素的高度也计算进去。利用bfc避免margin重叠也是同样的道理。3、BFC应用之:利用bfc特性实现左侧不固定,右侧也不固定的布局图片来自:张鑫旭–粉丝群第1期CSS小测点评与答疑如图:这种布局在移动端一般比较常见,左侧文字宽度不固定,右测文字宽度不固定,文字断行后也要保持同样的行距。在移动端中可以使用flex布局,grid布局,如果不使用css3布局,我们能否实现呢?答案是可以的,可以使用 浮动+bfc 特性!<style> body,dl,dd,dt,p{ padding: 0;margin: 0; } dl{ width: 30%; padding: 10px; border: 1px solid #ccc; margin: 10px auto; } dt{ float: left; margin-right: 25px; } dd{ margin-bottom: 10px; word-break: break-all; text-align: left;/* 为dd元素创建一个bfc,根据bfc布局规则第4条,bfc的区域会通过变窄来自适应而不会与float元素重叠在一起,所有这就达到了我们想要的效果。 / overflow: hidden; }</style><dl class=“dl2”> <dt>手机系统</dt> <dd>Android</dd> <dt>登录方式</dt> <dd>QQ互联登录</dd> <dt>绑定事件</dt> <dd>2019-01-02 00:01</dd> <dt>其他</dt> <dd>FAsfsdafsadfasdfSDsadfsadfsd4545454555454545sdafsdf</dd> <dt>备注</dt> <dd>如果需要修改绑定,请联系HR进行修改!</dd></dl>下图是dd创建了bfc与未创建bfc的对比:由图片可以看出,创建了bfc的dd的宽度自适应的变窄了,而未创建bfc的dd却与浮动的dt重合了。4、BFC应用之:利用bfc特性解决margin塌陷问题margin塌陷是一般指在标准文档流中,两个垂直排列的元素,一设置个margin-bottom,另一个设置margin-top,此时两个元素的margin就会发生重叠。margin重叠规则:1)margin的值都为正数时,取它们之间较大的值2)margin的值都为负数时,取两个margin绝对值中较大的值3)两个margin一正一负时,取两个margin相加的和margin塌陷与不塌陷效果:<style> body,dl,dd,dt,p{ padding: 0;margin: 0; } .float-container{ width: 30%; margin: 50px auto; padding: 10px; border: 1px solid #ccc; overflow: hidden; } .float-box{ / 元素浮动后就创建了bfc,两个元素就创建了两个bfc,根据BFC布局规则第5条,.float-container的高度会把浮动元素的高度也计 算进去;根据BFC布局规则第2条,两个.float-box分别创建了2个bfc,因此它们之间的margin并不会重叠 / float: left; width: 100%; height: 60px; margin: 20px 0; color: #fff; } .float-box:nth-child(1){background-color: #ccc;} .float-box:nth-child(2){background-color: #f10;} .no-bfc-container{ width: 30%; margin: 50px auto; padding: 10px; border: 1px solid #ccc; } .no-bfc-box{ height: 60px; margin: 20px 0; color: #fff; } .no-bfc-box:nth-child(1){background-color: #ccc;} .no-bfc-box:nth-child(2){background-color: #f10;} .bfc-box{ / 根据BFC布局规则第2条,.bfc-box创建了一个bfc,与第一个.no-bfc-boxbu元素不属于同一个bfc,因此两个.no-bfc-box元素的 margin也不会发生重叠 */ overflow: hidden; }</style><body> <div class=“float-container”> margin未塌陷 <div class=“float-box”>margin: 20px 0;</div> <div class=“float-box”>margin: 20px 0;</div> </div> <div class=“no-bfc-container”> margin塌陷 <div class=“no-bfc-box”>margin: 20px 0;</div> <div class=“bfc-box”> <div class=“no-bfc-box”>margin: 20px 0;</div> </div> </div></body>6、参考文章1、https://www.zhangxinxu.com/wo… (引导文章)2、https://www.zhangxinxu.com/wo…3、https://www.w3cplus.com/css/u…4、https://blog.csdn.net/w362427…5、https://blog.csdn.net/shadow_… ...

January 21, 2019 · 1 min · jiezi

一篇文章带拿下盒模型BFC渲染机制

走在前端的大道上本篇将自己读过的相关 盒模型BFC 文章中,对自己有启发的章节片段总结在这(会对原文进行删改),会不断丰富提炼总结更新。一.常见定位方案在讲 BFC 之前,我们先来了解一下常见的定位方案,定位方案是控制元素的布局,有三种常见方案:普通流 (normal flow)在普通流中,元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行,块级元素则会被渲染为完整的一个新行,除非另外指定,否则所有元素默认都是普通流定位,也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。浮动 (float)在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。绝对定位 (absolute positioning)在绝对定位布局中,元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响,而元素具体的位置由绝对定位的坐标决定。二、BFC 概念Formatting context(格式化上下文) 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。常见的FC有BFC、IFC,还有GFC和FFC。那么 BFC 是什么呢?BFC 即 Block Formatting Contexts (块级格式化上下文),它属于上述定位方案的普通流。一个BFC的范围 包含创建该上下文元素的所有子元素,但不包括创建了新BFC的子元素的内部元素。这从另一方角度说明,一个元素不能同时存在于两个BFC中。因为如果一个元素能够同时处于两个BFC中,那么就意味着这个元素能与两个BFC中的元素发生作用,就违反了BFC的隔离作用。具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。三、布局规则内部的Box会在垂直方向上一个接一个的放置每个元素的左外边距与包含块的左边界相接触(从左向右),即使浮动元素也是如此。(这说明BFC中子元素不会超出他的包含块,而position为absolute的元素可以超出他的包含块边界)属于同一个BFC的 两个相邻Box的 上下margin会发生折叠;BFC的区域不会与float的元素区域重叠(阻止元素被浮动元素覆盖)计算BFC的高度时,浮动子元素也参与计算(清除内部浮动)四、触发 BFC只要元素满足下面任一条件即可触发 BFC 特性:body 根元素浮动元素:float 除 none 以外的值,如left、right绝对定位元素:position (absolute、fixed)display 为 inline-block、table-cells、flexoverflow 除了 visible 以外的值 ,如hidden、auto、scroll注意:有些文章中说HTML可以触发BFC,没有说body,按照上边介绍的一个BFC的范围和下边的案例1 来看,HTML能不能触发不确定,但是body是可以的五、BFC的特性及应用1.普通流中两个相邻的块元素 垂直方向上的 margin会折叠<style>.p { width:200px; height:50px; margin:50px 0; background-color:red; } </style><body> <div class=“p”></div> <div class=“p”></div> </body>效果图是:发生外边距折叠,是因为他们 同属于 body这个根元素让 它们 不属于同一个BFC,就能避免外边距折叠:<style>.wrap { overflow:hidden; }.p { width:200px; height:50px; margin:50px 0; background-color:red; }</style><body> <div class=“p”></div> <div class=“wrap”> <div class=“p”></div> </div> </body> 效果图是:2.普通流中 父子嵌套关系的2个块元素 垂直方向上的 margin会折叠 <style> .father { width: 200px; height: 200px; background: skyblue; } .son { width: 100px; height: 100px; background: red; } </style> <body> <div class=“father”> <div class=“son”></div> </div> </body>然后,我们给子元素添加一个margin-top: 50px时.son { width: 100px; height: 100px; background: red; margin-top: 50px;}我们神奇的发现父子元素同时"掉下来了50px",如图所示3.BFC可以包含浮动的元素(清除浮动)正常情况下,浮动的元素会脱离普通文档流,所以下面的代码里:<style>.wrap { border: 1px solid #000; }.inner { float: left; width: 50px; height: 50px; background: #eee;}</style><body> <div class=“wrap”> <div class=“inner”></div> </div></body> 外层的div会无法包含 内部浮动的div,效果见下图:但如果我们 触发外部容器的BFC,根据BFC规范 计算BFC的高度时,浮动元素也参与计算,那么外部div容器就可以包裹着浮动元素,所以只要把代码修改如下:<style>.wrap { border: 1px solid #000; overflow:hidden; }.inner { float: left; width: 50px; height: 50px; background: #eee;}</style><body> <div class=“wrap”> <div class=“inner”></div> </div></body> 就可以完成以下效果:4.实现2栏自适应布局要求左侧固定300px,右侧自适应的布局 <style> .wrapper, * { padding: 0; margin: 0; } .left { width: 300px; height: 100px; background: red; float: left; } .right { height: 100px; background: skyblue; overflow: hidden; } </style> <div class=“wrapper”> <div class=“left”>left</div> <div class=“right”>right</div> </div>原理:BFC元素不会和浮动的元素重叠参考文章:10 分钟理解 BFC 原理CSS中重要的BFC浅析CSS里的 BFC 和 IFC前端人人都应该理解的盒模型BFC渲染机制 ...

January 13, 2019 · 2 min · jiezi

CSS2中盒模型与布局的一些概念关系

CSS的一些名词和概念用来帮你更明确地去描述HTML/CSS世界的事物。box在CSS中,一个元素就可以看作一个box。具体信息可以参考盒模型的解释,这里暂且不作展开。containing blocksBox的位置和大小时根据一个称为containing blocks的边界进行计算的。block-level elements 和 block boxesblock-level elements 一般指HTML中的特定类型的元素,比如div,p,ul等。block boxes 指形成一个block formatting contexts的boxes。可以确定的时正常的block-level(没有改变它的position,display等默认属性值)可以形成一个BFC。But,如果元素等display属性值为 ‘block’, ’list-item’, 或 ’table’中的一种,也可以对外表现出块级元素的行为。也会成为一个block box。BFC(Block formatting contexts)哪些情况会产生一个BFC:根元素float元素(float属性不是none)display: block,table-cell,table-captain,list-item, table、table-row、 table-row-group、table-header-group、table-footer-groupposition是absolute的元素(绝对定位)overflow不等于visibleflex 元素grid 元素在一个BFC中,形成一个独立的布局环境,里面元素等布局位置不会受外部元素影响。IFC (Inline formatting contexts)与BFC对应,一个行内元素默认也会形成一个IFC(行内格式化上下文)。IFC有个不同于一般的常识的特性:当inline-level box宽度大于父容器宽度时会被拆分成多个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;<p style=“margin-left:100px;margin-right:20px;border:1px dashed #ccc;"> <span class=“before”> before </span> <span class=“cotent” style=“margin-left: 100px; margin-right: 20px;"> An inline box is one that is both inline-level and whose contents participate in its containing inline formatting context. A non-replaced element with a ‘display’ value of ‘inline’ generates an inline box. Inline-level boxes that are not inline boxes (such as replaced inline-level elements, inline-block elements, and inline-table elements) are called atomic inline-level boxes because they participate in their inline formatting context as a single opaque box. </span> <span class=“after”> after </span></p>注意示例中,content 元素这段话开头和结尾的外边距大小。在CSS2中, 一个盒子的定位模式通常是一下三种:Normal flow:正常的文档流是由 BFC、IFC和position是relative的 block boxes或inline boxes 组成。Floats float属性值不等于none的元素通常称之为浮动元素。absolute positioning (绝对定位元素) 绝对定位的元素完全从正常的文档流中移除,它的位置不会影响它后面元素的位置。positioned elementposition属性值不是static的元素称之positioned element。display,position和float的相对关系我们知道,display,position和float都会对元素的布局位置表现产生影响。那么它们三者之间是如何起作用的呢?如果display:none; position和float将不会再起任何作用;如果position属性是absolute或fixed,则float属性置为none(可以理解为不再存在float行为,即使手动设置了float不为none), display行为依据下表的规则展示;元素的定位会依据top/right/bottom/left进行计算。如果float属性值不为none,则display属性依据下表的规则展示;如果元素是根元素,则display的展示依据下表规则表现。其它情况,依据display设定的值进行处理指定值最终表现值inline-tabletableinline, table-row-group, table-column, table-column-group, table-header-group, table-footer-group, table-row, table-cell, table-caption, inline-blockblockothers与指定值相同 ...

January 6, 2019 · 1 min · jiezi