一 前言
众所周知,HTML、CSS、JavaScript是所有网页技术的基础与核心。HTML 是语义,CSS是控制信息,JavaScript是逻辑、动态。HTML定义了大量标签并赋予各个标签以特定的含义及默认的显示方式,例如 <img> 标签代表图片元素;而CSS控制着这些标签如何呈现出来 ,及通常所说的渲染,如各个标签的位置和层。JavaScript 是一种动态语言,有了HTML和CSS后,网页仍只是静态的,如何动态的操作这些标签?当前这由JavaScript 完成, 但不排除后面出现新的语言,或者JavaScript的变体。
本文档将介绍CSS2.1规范及其在WebKit中的实现。 下面给出本文档涉及的术语定义:
- absolutely positioned: absolute or fixed 定位,见规范9.6
- positioned element: 除static定位外的元素,见规范 9.3.2
- replaced element, 该元素的内容(如何渲染该元素)不由CSS 规范描述,即该元素的外观、尺寸等由外部资源确定,如 HTML 的<img>元素; replaced element 通常有 src属性 , “intrinsic”width/height, 见规范 3.1
- stack context: 层叠上下文
二 CSS 规范
2.1 Box Model
2. 1 Controlling box
由上知,在网页渲染过程中,每个元素都会被当做box来排版。在CSS 2.1 中定义了三类box, 由display 属性指定:
- block box, 垂直方向layout
- inline box, 水平方向 layout
- run-in box , run-in box 是比较特殊的box,遵循如下规范:
1. 如果 run-in box 包含 block box,那么这个 run-in box 也成为 block box
2.如果紧跟在 run-in box 之后的兄弟节点是 block box,那么这个 run-in box 就会做为此 block box 里的 inline box,run-in box 不能进入已经一个已经以 run-in box 开头的块内,也不能进入本身就是 display:run-in;
的块内
3. 否则,run-in box 成为 block box 不过WebKit 并不严格遵循run-in box模型。 html 标签元素究竟产生block box 还是inline box 取决于如下两个因素:
- 标签本身
- css的display 属性
在HTML 规范定义了Block element 、inline element, 一般具有如下区别:
- block-level elements generally can contain text, data, inline elements, or other block-level elements.
- block-level elements generally begin new lines of text.
- block-level elements inherit directionality information differently from inline elements.
如,div 标签为block-level element, <a>为inline-level 元素, http://htmlhelp.com/reference/html40/block.html 给出了所有的block-level element, http://htmlhelp.com/reference/html40/inline.html 给出了所有的inline-level element。
回到html 标签元素究竟产生block box 还是inline box的话题,一般情况下block-level 产生block box, inline-level 元素产生inline box。 但是,这可以通过 css的display 属性改变。
display 属性的使用见: http://www.w3school.com.cn/css/pr_class_display.asp 。
2.3 定位
根据2.1、2.2,每一个元素处理成一个box,但如何安排所有的box,确定每个box的位置? 这就是定位(position)。一般定位的过程分为如下几步:
- 首先需要确定参考坐标系;
- 其次根据参考坐标,确定其定位算法
- 计算位置信息
css的定位机制也不例外。
2.3.1 containing box
containing box就是定位过程中的参考系。 在CSS 2.1 的 9.2.1、10.对containing box 有相关介绍。 在CSS 2.1中, 许多box 的位置和尺寸都根据一个规则的矩形box的边缘来确定,这个规则的矩形box就是containing box。 一般来说,generated boxes对其后代boxes承担containining box的作用;对其,我们认为该box对其后代extablishes containing box 。 ‘a box’s containing box ’意味着 该box 所live的 containing box 而不是其产生的 containing box。
containing box的确定过程如下:
- 用户代理(比如浏览器)选择根元素作为 containing block(称之为初始 containing block);
- 对于其它元素,除非元素使用的是绝对位置,containing block 由最近的块级祖先元素盒子的内容边界组成;
- 如果元素有属性 ‘position:fixed’,containing block 由view port (视口)建立。 fixed 和absolute的区别
- 如果元素有属性 ‘position:absolute’,containing block 由最近的 position 不是 static 的祖先建立,按下面的步骤:
如果祖先是块级元素,containing block 由祖先的 padding edge 形成 (见box-model 图)
如果祖先是内联元素,containing block 取决于祖先的 direction 属性;
如果 direction 是 ltr(左到右),祖先产生的第一个盒子的上、左内容边界是 containing block 的上方和左方,祖先的最后一个盒子的下、右内容边界是 containing block 的下方和右方;
如果 direction 是 rtl(右到左),祖先产生的第一个盒子的上、右内容边界是 containing block 的上方和右方,祖先的最后一个盒子的下、左内容边界是 containing block 的下方和左方。
- 如果没有祖先,根元素盒子的内容边界确定为 containing block。
2.3.2 flow
CSS 用flow来代表定位算法。 当前包括: normal flow、float flow 和 absolutely flow,如下:
Normal Flow 是CSS 2.1规范中定义的,在一般通俗文档中被表述为“文档流”,是最重要的定位机制。 其通俗描述为 将窗体自上而下分成一行行,并在每行中按从左至右的顺序排放元素,即为文档流。在规范中如下定义:
- 任何被渲染的元素都是一Box, block box 或者 inline box,但不能同时属于这两类;
- Normal flow 定位过程包括 包括 block formatting context 、inline formatting context 、Relative positioning 三个过程;
- block formatting context: 块级元素按照其在HTML中的顺序,在其容器框里从左上角开始,从上到下垂直地依次分配空间、堆砌( stack ),并独占一行,边界紧贴父容器。两相邻元素间的距离由 margin 属性决定,在同一个 block formatting context 中的垂直边界将被重叠( collapse )。并且,除非创建一个新的 block formatting context ,否则块级元素的宽度不受浮动元素的影响(这就是浮动元素能盖在块级元素上面的原因)
- inline formatting context: 行内元素从容器的顶端开始,一个接一个地水平排布。水平填充、边框和边距对行内元素有效。但垂直的填充、边框和空白边不影 响其高度。一个水平行中的所有 inline box 组成了名为 line box 的矩形区域。 line box 的高度始终容下所有的 inline box ,并只与行高有关。 line box 的宽度受到父容器和浮动元素存在的影响(这就是文本环绕浮动元素)。如果 line box 的宽度小于容器, line box 的水平排布就取决于 text-align 。如果 line box 的宽度大于容器,则截断 line box 并换行在新的 line box 中重新排布元素(截断处不应用 padding 和 margin 值)。如果 line box 无法截断,如单词过长或者指定不换行,则会溢出容器;
- elative positioning: 对这些 block box 和 inline box 进行相对定位,即相对于已排布的位置进行偏移。元素在其中保留原来所占用的空间
看到这里,读者可能会问,什么时候开始block formatting context,什么时候属于inline formatting context? 下面的这些情况,将会创建一个新的 block formatting context
- 根元素
- 浮动或绝对定位的元素
- display 值为 inline-blocks , table-cell 或 table-caption
- overflow 值为非 visible
当block-level box作为block containing box时,见2.3.1,其可能仅仅包括其他的block
box ; 或者创建新的 inline formatting context, 此时,其内只能包括inline boxes。 因此,block
box 内要么只有其他的block box,要么只有 inline box,不能同时拥有,(如果其内既包括inline和block元素时,将产生匿名box以确保上述条件形成),也就是说,当只有inline box时将创建 inline formatting context。下面是Normal Flow的三个特性:
1、默认情况下,相邻的文档元素根据先后顺序从左到右,从上到下,按照 display 属性来布局元素(分行或不分行);
2、脱离Normal Flow 的元素:定位属性 position 的属性值为 absolute、fixed 的元素会脱离Normal flow
3、如果元素没有定义高度,元素所包含的内容会把元素撑开,但是脱离Normal Flow 的元素不会占据父元素的布局空间因此无法撑开父元素高度,浮动元素仍占据父元素的布局空间,但无法撑开父元素的高度接下来看看Floatflow,float元素定义元素浮动到左侧或右侧,以往这个属性一般应用于图像,使文字围绕在图像周围,有如下几个要点。
* 浮动元素的布局是基于的,不会完全脱离normalflow
* 浮动元素将按 inline-block 形式布局(haslayout),即使将他设置为 display:inline;
* 浮动元素仍占据父元素的布局空间,但无法撑开父元素的高度
最后看看 absolute 和fixed 定位。 这两类元素定位的算法是一样的,区别只在于确定其containing box的方式
不一样,见2.3.1.由上面知 absolute/fixed 元素从normalflow中完全脱离出来,确定新的block formatting context,其子元素或子absolute/fixed元素将按照一般的Normalflow进行定位;An absolutely positioned box extablishes a new containing block fornormalflowchildren and absolutely (but not fixed) positioned descendats.。
2.3.3 display float 和position 的关系
- 浮动元素的布局是基于Normal flow的,不会完全脱离Normal flow
- 如果 display 的值为none, 则忽略position与float, 这种情况下, 元素不产生box
- 否则, 当positon为absolute时,float的属性就会失效,display的属性 参考下表,从下表知道,inline-table 变成table,其他都会变成block,即即使是inline成为block。
- 当float为left或right时, display参考下表,由表知道,无论是否设置display:block,浏览器都会当成block来处理。
- 浮动元素对自身的影响:浮动元素将按 inline-block 形式布局(haslayout),即使将他设置为 display:inline;
2.3.4 其他
1. inline boxes 中包括 block boxes的情况: 当inline box中包含 block box时, 该inline (和它在同一个inline box中的 inline 祖先一起)被该block box 打破,inline box 被拆分成2个inine box,两个 inline box 处于block box的两头;前后两个inline boxx都将各自产生一个anonymous block box ,产生的anonymous block box 跟先前的block box 相邻。如果该inline box 是相对定位,则对该inline box的任何 “平移”(偏移)结果都将影响了该inline box内的block box。
2.4 分层
2.3节定位决定了每个元素的(x,y)位置,但是如何显示呢? 元素(x,y)出现重叠时怎么处理呢? 这就是本节提到的分层的主题。把网页看成一个立体结构,定位决定了其x-y坐标,显然还缺z坐标。 这可通过css 的z-index属性指定。 z-index : 仅仅应用于positioned elements (即除static外的元素),想想为什么? 思考什么情况下才会出现重叠? 。
使用如下:
z-index="integer/auto", integer是生成box在当前层叠上下文中(stack context)的层叠级别,越打层级越高; 如果为auto,则生成box在当前层叠上下文中的层叠级别和它的父box相同,因此不会产生新的层。
stack contex ,层叠上下文:
css 层叠的结构,涉及层叠上下文,层叠上下文是一个抽象的容器,它可以包含层,也可以包含其子元素创建的层叠上下文。在层叠上下文内部,各层按照规则在 Z 轴方向上从后向前排列。从一个父层叠上下文的角度来看,层叠上下文本身是其中一个不可分割的最小单位;其他层叠上下文中的框,不可 能出现在它里面的框的中间位置。 也就是说,层叠上下文本身被看作一个单独的层处理,它在 Z 轴上的顺序与其子层无关。在给定的层叠上下文中,每个元素都有一个整型的层叠级别,它描述了在相同层叠上下文中元素在“Z轴”上的显示顺序。同一个层叠上 下文中,层叠级别大的显示在上,层叠级别小的显示在下,相同层叠级别的框会根据文档树中的位置,按照前后倒置的方式显示。根元素形成根层叠上下文。其他层 叠上下文由任何 ‘z-index’ 计算后的值不是 "auto" 的定位元素生成。不同层叠上下文中,元素显示顺序以父级层叠上下文的层叠级别来决定显示的先后顺序。与自身的层叠级别无关。
层叠上下文的构成:
每个层叠上下文都有如下的层组成(显示顺序从后到前):
- 形成层叠上下文的元素的背景和边框
- 层叠级别为负值的后代层叠上下文
- 常规流内非行内非定位的子元素组成的层
- 非定位的浮动子元素和它们的内容组成的层
- 常规流内行内非定位子元素组成的层
- 任何 z-index 是 auto 的定位子元素,以及 z-index 是 0 的层叠上下文组成的层
- 层叠级别为正值的后代层叠上下文
示意图:
细节请参考: http://www.w3help.org/zh-cn/kb/013/
2.5 Visual effets
如何控制元素是否可见?元素溢出(overflow)时如何显示?这牵涉到 overflow、clipping、visibility属性。
- overflow: 应用于 non-replaced block-level elements, table cells and inline-block elements
- clip: 应用于 absolutely positioned elements (absolutely and fixed),设置可见区域,思考为什么只用于absolutely positioned elements?
- visibility: 应用于 all elements ,即使为hidden 也参与layout (display:none 的元素才不参与 layout)
下表是overflow的取值:
下表是clip的取值:
下表是visibllity的取值:
2.6 CSS尺寸表示
css尺寸表示包括绝度度量和相对度量,如下:
三 总结
CSS 主要究竟都包括哪些呢? 下图做了简单总结:
介绍就到这了,留下几个问题:
- CSS究竟是什么? CSS每个规则应用的主要场景是什么,例如float?
- 其Noraml flow 为什么这么设计? 优点是什么?缺点是什么?
- CSS的改变什么情况下容易导致重新layout,从而影响性能? 如何避免?
- 元素如何应用css?css的优先级如何确定? 这类代码应如何写效率比较高?
- CSS 绘制时,是根据分层来逐层绘制吗? 分层在什么情况下产生?分层跟layout有什么关系?
- CSS的排版机制跟其他排版机制的区别? 例如GUI中控件位置, book的排版,word等。
- 你最希望CSS 还具备什么功能? 哦,看CSS3吧?!
四 参考文献
https://developer.mozilla.org/en/CSS/Visual_formatting_model Visual formatting model
http://mattryall.net/blog/2008/08/css-layout-fundamentals-block-and-inline-boxes CSS layout fundamentals, part 3: block and inline boxes
http://blog.sina.com.cn/s/blog_616a82920100yshb.html Block Boxes VS Inline Boxes
http://www.w3help.org/zh-cn/kb/013/ 分层的显示( Layered presentation )
http://www.w3help.org/zh-cn/kb/008/ containing block
http://www.swordair.com/blog/2011/03/577/ Block-level Box & Block Container Box & Block Box
http://www.swordair.com/blog/2010/08/415/ CSS 普通流(Normal flow) (文档流)
http://www.cftea.com/c/2009/01/4ADRBHOD480VEFRW.asp containing box
http://www.swordair.com/blog/tag/run-in-display/ CSS:displaty run-in
http://www.w3school.com.cn/css/pr_class_position.asp CSS position 属性
http://hi.baidu.com/smartcarlf/blog/item/8b23c404c8d425d27b89473d.html 元素布局中的 display 、position、float
摘自三生石畔的博客,原文链接已丢失