|
一些基本概念
viewport: 展现网页的媒体,比如窗口或者某个区域,它的大小是有限制的,为了不被平台术语所束缚,
我们给他起名viewport,中文意思就是视口。
canvas: 而我们在渲染网页的时候通常并不知道我们需要多大的空间,而且这些空间通常尺寸会超过vie
wport的大小,于是实际上我们需要设想一个无限大的画布来绘制我们的元素,我们把它称为canvas。
box: element(元素)和node(节点)是大家很熟悉的概念,当我们做布局计算的时候,通常会把节点变
成box,一个节点可能产生多个box,伪元素也会产生box。
render tree: 对应于dom树,我们把box的包含关系构成的属性结构成为渲染树render tree
BFC
首先我们来考虑一个基本的情况:
- <p>
- </p><p>run</p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style="width:300px;height:50px;"></div></p><p> <div style="width:300px;height:20px;"></div></p><p> <div style="height:50px;"></div></p><p> <div style="width:300px;height:50px;"></div></p><p> </body></p><p></html></p>
复制代码
之所以简单是因为这些div每一个只产生一个盒子,默认的display下,div产生块级盒,为了让块级盒按照
我们的意愿排布,我们需要引入一个概念:block formatting context,简称BFC。
BFC其实是个相当简单的概念,然而因为实在中文中没啥合适的词来形容(你不觉得"块级格式化上下文
"比BFC更让人觉得不知所云么?),这个概念已经被传得极其神秘:
在 CSS 面试中问 BFC 等概念,就如在 JS 面试中问闭包等概念一样,经常会刷掉一些真正优秀的人。 —
—玉伯
甚至很多人连它是动词还是名词都搞不清,不信你可以搜索一下触发BFC,亲,BFC是名词啊……怎么它
就能触发呢?
简单地说,BFC就是像例子里面一样顺次竖着排块级盒的一种上下文。竖着排盒子而已,竖着排盒子有什
么理解不了的啊我X?
好吧平复一下情绪,我们继续说,canvas会设立一个BFC,这也是最外层的formatting context了,问题
的复杂性在于有些块级盒内部也可以产生BFC(至少它必须也能包含块级盒),于是说BFC是可以嵌套滴:
- <p></p><p>
- </p><p>run</p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style="width:300px;height:100px;"></p><p> <div style="width:300px;height:20px;"></div></p><p> <div style="height:50px;"></div></p><p> </div></p><p> <div style="height:50px;"></div></p><p> </body></p><p></html></p><p>不是所有块级盒内部都可以产生BFC,比如说要是这盒里面连块级盒都没有,都是行内盒那就产生IFC:</p><p>
- </p><p>run</p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style="width:300px;height:100px;overflow:visible;"></p><p> <span>囧</span><span>囧囧</span></p><p> </div></p><p> <div style="height:50px;"></div></p><p> </body></p><p></html></p><p>不过,只要它的子节点里面有一个块级盒,它就产生BFC,那些行内元素,会自动套一个匿名的块级行盒。</p><p>
- </p><p>run</p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style="width:300px;height:100px;overflow:visible;"></p><p> <span>囧</span><div>啦啦啦</div><span>囧囧</span></p><p> </div></p><p> <div style="height:50px;"></div></p><p> </body></p><p></html></p>
复制代码
又比如说overflow:visible的块盒就不产生BFC,不但不产生BFC,啥FC都不产生,它的子元素直接搞进自
己外层的BFC鸟:
- <p>run</p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style="width:300px;overflow:visible;"></p><p> <p style="width:200px;height:20px;"></p></p><p> <p style="height:50px;">aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa</p></p><p> </div></p><p> <p style="height:50px;"></p></p><p> </body></p><p></html></p>
复制代码
overflow:visible这个限制只对所谓的块盒(既包含块级盒、自己又是块级盒)存在,有些盒内部也能包
含块级元素,但是它本身又不是块级元素(比如display为table-cell、inline-block、或者盒本身是flex item
等),因为外面不是BFC,所以它们不论如何一定会给包含的块级盒创建一个新的BFC出来。
同一个BFC里面的盒还会有margin collapse现象,详情见此文 《谈margin collapsing(外边距叠加)》
IFC
IFC里面可能有文字、行内元素混合排布:
run
- <p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style=""></p><p> <span>囧</span>囧囧囧<span>囧囧</span></p><p> </div></p><p> </body></p><p></html></p>
复制代码
文本的排布是个很复杂的事情,在dom树中,我们存储的是字符和字符串,而在render tree中,我们要使
用一个新的概念:字型(glyph)。字体文件(通常是ttf,ture type格式的)中包含着不同字体下字符到
字型的规则。
一个字型有很多属性,下面这张图来自freetype,它是大部分浏览器使用的文字排版基础库:
详情请看这里。
图中的那根加粗的X轴就是传说中的基线(base line)了,文字默认是按照基线对齐的。
下面这个demo展示了一个IFC中的几条重要的基准线:
great it works!2囧啊
在水平方向,文字的排布主要受到以下属性影响
word-break, word-spacing, word-wrap
letter-spacing
white-space
text-align
hyphenate-character, hyphenate-limit-after, hyphenate-limit-before, hyphenate-limit-lines, hyphens
justify-content
……
总之很复杂,讲也讲不完,而且大家又不要写浏览器所以大家就大概望文生义一下好了(po主被扔蛋中……)。
对于一个正常的"行盒"来说,文字总是垂直居中排布的。
在纵向,文本排布主要受line-height属性影响,在有行内盒参与的情况下就复杂了,
一个行内盒的vertical-align可以有这样几种取值:
- <p>baseline</p><p>sub</p><p>super</p><p>top</p><p>text-top</p><p>middle</p><p>bottom</p><p>text-bottom</p><p>它也可以是某一指定高度。根据行内盒的对齐方式,它有可能把这行盒向上或者向下"撑大",造成超过行高的情况。</p><p>
- </p><p>所以行盒在BFC中占据的实际高度,很可能大于line-height。</p><p>
- </p><p>文字的baseline很好理解,而行内元素则比较复杂,特别是当行内元素自身又是容器的时候:</p><p>
- </p><p>run</p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style="overflow:visible;"></p><p> <span>囧</span>囧囧囧<div style="display:inline-block;width:300px;height:300px;"></div><span>囧囧</span></p><p> </div></p><p> </body></p><p></html></p><p>run</p><p>
- </p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style="overflow:visible;"></p><p> <span>囧</span>囧囧囧<div style="display:inline-block;width:300px;height:300px;">123<br/>123<br/>123</div><span>囧囧</span></p><p> </div></p><p> </body></p><p></html></p><p>浮动</p><p>浮动是个行级的行为,当遇到浮动元素的时候,会首先"假装"它是个行内元素进行排版,排好后就往浮动的方向挤到挤不过去为止(遇到边界或者其它浮动元素)。</p><p>
- </p><p>run</p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style=""></p><p> <span>囧</span>囧囧囧<div style="display:inline-block;width:300px;height:300px;float:left"></div><span>囧囧</span></p><p> </div></p><p> </body></p><p></html></p><p>run</p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style=""></p><p> <span>囧</span>囧囧囧<div style="display:inline-block;width:300px;height:300px;float:left"></div><span>囧囧</span><br/></p><p><div style="display:inline-block;width:300px;height:300px;float:left"></div></p><p> </div></p><p> </body></p><p></html></p>
复制代码
某一方向有clear的时候,浮动元素总是挤到边界,在垂直方向上的行为类似"换行"。
- <p>run</p><p>
- </p><p><html></p><p> <head><title>囧</title></head></p><p> <body></p><p> <div style=""></p><p> <span>囧</span>囧囧囧<div style="display:inline-block;width:300px;height:300px;float:left"></div><span>囧囧</span><br/><div style="clear:left;display:inline-block;width:300px;height:300px;float:left"></div></p><p> </div></p><p> </body></p><p></html></p>
复制代码
排好一个浮动元素之后,这一行就要重排一次。所以说浮动元素会造成行级的reflow。重排的时候,
行盒会躲开浮动元素。之后的块级盒(不论是行盒还是其它盒)也都会躲开浮动元素排布。
最后赠送文中使用的查看盒边框的小工具,欢迎自己来写网页看盒子:
run
|
|