一、定位基本原理
对于前端开发工程师来说,编写CSS是前端开发工作中必不可少的一个内容,在CSS中的position属性又是非常重要的一个方面。顾名思义,所谓position,即是对HTML元素定位方式的一种设置。它是CSS定位技术的基石,看似很容易学习,很多的前端工程师也会说自己掌握得很好,但事实上是这样吗?作为一个在前端开发的道路上慢慢前行的新人,我不敢这么说,那么就通过这篇文章与大家一起,了解position的奥秘。
首先,既然是CSS中的属性之一,那么我们就有必要研究一下W3C的CSS文档,毕竟这才是对此属性说明最为详细的地方。在这里要插一句,目前市面上充斥着大量的教学书籍,网络上也有很多相关的学习资源,其中固然不乏精品,但是会花点时间,认真阅读官方文档的又有多少人呢,有的时候,最乏味的往往是最准确的。
好了,话不多说,官方文档中关于position属性的内容大致是这样的:
In CSS 2.1, a box may be laid out according to three positioning schemes:
1、Normal flow
2、Floats
3、Absolute positioning
1. 常规文档流。包括块级元素排版,行内元素排版以及对块级元素和行内元素相对位置的排版。
2. 浮动。在浮动模型中,元素先按照正常文档流定位,然后从文档流中移出,根据设置向左或者向右尽可能地移动。
3. 绝对定位。元素会完全从文档流中移出,再根据父元素进行定位。
一个元素如果是根元素,或者有浮动或绝对定位的话,那它就是在常规文档流之外的,其他情况都是在文档流之内。文档中有这么一句:The flow of an element A is the set consisting of A and all in-flow elements whose nearest out-of-flow ancestor is A. 有些绕,以我并不深厚的英语能力来翻译的话,应该是:元素A的flow是由元素A本身以及所有最近的文档流之外的父元素是A的流内元素所组成的。(翻译得太惨不忍睹了,求大神指点o(>﹏<)o)。
二、position属性详解
在CSS 2.1中,元素的定位方式是由position和display属性共同作用所决定的,我们先来看position属性
position属性的可取值:static | relative | absolute | fixed | inherit
默认值:static
每个值的意义:
static: 常规方式定位box,此时设置top, right, bottom, left属性是无效的。
relative: 元素本身的的位置的定位方式和static是一样的,但是实际位置会相对于原位置有所偏移,是通过top, right, bottom, left的设置实现的。注意:display设置为table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell和table-caption的元素是无法应用position: relative的,这也很好理解,这些表格类元素如果会相对于正常位置偏移的话不是很奇怪么!
absolute: 元素脱离文档流,“几乎”独立了。位置通过top, right, bottom, left来设置,当然,参照基点是包含元素的父元素~绝对定位的元素对相邻元素的定位没有任何影响,相互之间的层叠关系是通过z-index来设置的,同时,绝对定位元素的margin之间也不会发生折叠。
fixed: 这是个比较有趣的值。它的定位计算方式和绝对定位是一样的,但是也有不同。元素的位置一旦确定了,在屏幕显示器上,它会保持固定不动,在印刷媒体类型上,它会在每页出现在固定位置,在其他的媒体类型上,表现方式则没有定义。不过,如果希望一个box在屏幕和印刷媒体上的表现不同的话,可以使用@media rule的方式,例如:
CSS Code复制内容到剪贴板 @media screen { h1#first { position: fixed; } } @media print { h1#first { position: static; } }还有一个inherit值,不用多说,就是从父元素继承position值了。
三、定位方式:top, right, bottom, left
这四个属性其实可以放在一块儿说,其实是差不多的,只是定位的相对基线变了而已。文档上的说明有些啰嗦了,不过thats what official document is对吧?
可设定的值为:length, percentage, auto, inherit
不论设定的值为什么,意义都是元素的上右下左距离父元素的上右下左的边距。
这里要提一下auto值,对于非替换元素(non-replaced elements)和替换元素(replaced elements)auto的表现是不一样的,非替换元素指的是浏览器根据标签的元素和属性来判断具体显示的内容,如:
XML/HTML Code复制内容到剪贴板 <input type="text" />这是一个文本输入框,换成其他的属性的话,浏览器的显示就会不一样。
替换元素的例子:
XML/HTML Code复制内容到剪贴板 <p>Im classicemi</p>(X)HTML的大多数元素都是非替换元素,他们将内容直接告诉浏览器,浏览器再显示出来。
下面回到auto上来,对于非替换元素,auto值的效果取决于哪些相关的属性同样具有auto值,比较难理解是吗,好的,我们给出下面的例子:
CSS Code复制内容到剪贴板 <!DOCTYPE html> <html> <head> <title>A frame document with CSS 2.1</title> <style type="text/css" media="screen"> body { height: 8.5in } #header { position: fixed; width: 100%; height: 15%; top: 0; rightright: 0; bottombottom: auto; left: 0; } #sidebar { position: fixed; width: 10em; height: auto; top: 15%; rightright: auto; bottombottom: 100px; left: 0; } #main { position: fixed; width: auto; height: auto; top: 15%; rightright: 0; bottombottom: 100px; left: 10em; } #footer { position: fixed; width: 100%; height: 100px; top: auto; rightright: 0; bottombottom: 0; left: 0; } </style> </head> <body> <div id="header"> ... </div> <div id="sidebar"> ... </div> <div id="main"> ... </div> <div id="footer"> ... </div> </body> </html>在浏览器中显示的布局大致是:
代码中,使用了auto的属性有: #header bottom, #sidebar right, #footer top. 而对于#main呢,它的height和width都是auto,也就是说main的长宽是自适应的,自动填充可用空间,这也就好理解了,所谓的auto,也就是使元素的上右下左距离能够根据相关联的,或者说共同父元素的子元素之间的关系自动调整。
四、Normal Flow
前面提到了很多次“常规文档流”,实际上也就是W3C文档中的Normal Flow,也可称为常规流。常规流的理解,主要围绕着两个方面,分别是格式化上下文(Formatting Context)和相对定位(Relative Positioning)。
格式化上下文,按照W3C文档的解释,分为Block Formatting Contexts(BFC)和Inline Farmatting Contexts(IFC),这里我觉得没有什么翻译成中文的必要了,因为如果我说“块级格式化上下文”的话,诸位能理解是什么意思吗,所以,叫BFC和IFC就挺好。
所谓BFC,文档上解释得挺啰嗦,简单来说,就是块级box顺次垂直排列。当然也不能这么简单,原因是块级box的内部还会产生BFC,也就是说可以嵌套。
CSS Code复制内容到剪贴板 <!DOCTYPE html> <html> <head> <title>BFC</title> <meta charset="utf-8" /> </head> <body> <div style="width: 400px; height: 300px; background: blue;"> <div style="width: 200px; height: 100px; background: red;"></div> <div style="width: 100px; height: 150px; background: green;"></div> </div> </body> </html>但是,当块级box内部都是行内box的时候,就不会产生BFC,而是产生IFC,但只要子元素中有一个块级box,就会产生BFC。Attention! 文档中指出,如果外层块级box的overflow: visible; 的话,不会产生BFC甚至IFC。
下面来看看IFC,IFC中包括文字以及行内元素,对于文字来说,排版实际上有很多名堂,尤其是对于英文字符,或者说字母类文本,如果各位对文字排版有兴趣的话,推荐各位一部视频教程,由美国著名IT教学网站lynda.com出品的网页设计排版视频教程《Typography.for.Web.Designers》,至于下载方法,这里就不多说了,相信大家各显神通都有办法。
如果在行内元素中同时包含文字的话,情况会比较复杂:
CSS Code复制内容到剪贴板 <!DOCTYPE html> <html> <head> <title>IFC</title> <meta charset="utf-8" /> </head> <body> <div style="width: 400px; height: 300px; background: blue; overflow: visible;"> <span style="font-size: 20px;">Something</span> <div style="display: inline-block; width: 200px; height: 100px; background: red;"></div> </div> </body> </html>注意观察span和div的底部对齐差异。
行内框在行框垂直方向的对齐:
行框高度总是足够包含其容纳的所有框,它可能会高于它包含的最高的框。在这里会跟vertical-align属性相关:
vertical-align可能的取值:
baseline、sub、super、top、text-top、middle、bottom、text-bottom、length、%、inherit
举一个例子:
CSS Code复制内容到剪贴板 <!DOCTYPE html> <html> <head> <title>Vertical-align</title> <meta charset="utf-8" /> </head> <body> <p style="background: grey; width: 600px;"> <span style="font-size: 50px; border: 1px solid red;">hello</span> <span style="font-size: 30px; border: 1px solid green; vertical-align: top;">world</span> </p> </body> </html>在水平方向上的对齐:
行内框宽度总和小于包含框的宽时,水平方向的对齐取决于text-align属性。
五、POSITION和OVERFLOW的关系
父节点设置overflow:scroll,但是不管滚动条如果滚动,但是子节点一直都不动。当父节点不设置position情况下,子节点position的四种值的分析:
示例1.1:
CSS Code复制内容到剪贴板 body{ A {overflow: scroll;} A-1 {} }
效果:A-1会根据A滚动条的滚动而滚动
分析:A-1的默认position设置为static,当position为static时,A-1元素还是遵循正常的文档流,因此A-1会受它父节点属性的影响
示例1.2:
效果:A-1会根据A滚动条的滚动而滚动
分析:当A-1的position设置为relative时,A-1元素还是遵循正常的文档流,因此A-1会受它父节点属性的影响
示例1.3:(重点)
效果:A-1不会根据A滚动条的滚动而滚动
分析:当A-1的position设置为absolute时,A-1元素脱离了文档流,所以A-1不再受父节点属性的影响
注意:这时在父节点没有设置position的时,只会受到body节点的影响
示例1.4:
效果:A-1不会根据A滚动条的滚动而滚动
分析:当A-1的position设置为fixed时,A-1元素脱离了文档流,这时A-1只受body元素的影响
当父节点设置position值为非static情况下,子节点position的四种值的分析:
示例2.1:
效果:A-1会根据A滚动条的滚动而滚动
分析:跟示例1.1一样,当父节点A设置了position之后,子节点A-1还是遵循正常的文档流,因此A-1会受它父节点属性的影响
示例2.2:
效果:A-1会根据A滚动条的滚动而滚动
分析:跟示例1.2一样,当父节点A设置了position之后,子节点A-1还是遵循正常的文档流,因此A-1会受它父节点属性的影响
示例2.3:(重点, 注意跟1.3示例对比)
效果:A-1会根据A滚动条的滚动而滚动
分析:当父节点A设置了position之后,效果就跟示例1.3不一样了,这时A-1会受到离它自己最近的一个设置了position属性的父节点的影响,再看下面一个示例:
注意:这时A-1-1不会收A-1的影响,但是会受到A的影响
示例2.4:
效果:A-1不会根据A滚动条的滚动而滚动
分析:跟1.4示例一样,当子节点的position属性设置为fixed之后,不管的父节点是否设置了position值,都只会受到body节点的影响,其他任何节点都不会影响它