本文同时发表于本人个人网站 www.yaoxiaowen.com
在正式讨论position之前,我们需要知道几个概念。
块元素:独占一行的元素。比如div,h1~h6,p等,它是自带换行的。
内联元素:就是和相邻的内联元素同在一行的元素,比如span,a,img,small,em之类的。
以上内容是从是否独占一行的角度来说的,从另一个角度来说,也分为两种。
替换元素:就是浏览器根据标签的属性和内容来判断具体显示的内容。input,img,textarea等属于此类,以input为例。<input type=“text”/> 它是个文本输入框,而<input type=“button”/>它就是个按钮了。
非替换元素:绝大部分标签都是非替换元素。就是该标签直接告诉浏览器要显示的内容。比如<p>yaoxiaowen.com</p>.
像width,height,padding,margin之类的,都是适用于块元素的属性,内联元素设置了也不会有什么效果。。当然,他们默认如此。但是通过display属性,我们也是可以进行转换的。比如 display: block; 让内联元素也可以拥有块元素的属性,。display:inline,块元素也可以显示为内联元素。
而很简单,也是最重要的概念,流(Flow):简单来说,就是一份不包含任何css样式的html文档,是如何在浏览器中显示的。html文档,被浏览器从行到下,从左到右的顺序读取,这个顺序也就是它显示的顺序。在html文档中所写的第一个元素,那么在浏览器中也是第一个显示的。html文档中的第二个元素,浏览器中也是第二个显示。很简单的依次类推。。但是有区别的是,如果是块元素,那么它就独占一行。它后面的内容自然的从上到下排在它后面。而内联元素, 则自然的从左到右排列。可是浏览器的宽度总是有限的。内联元素一个挤一个,集满了这一行之后呢,那么它会自动的到下一行。
文本内容(字符串)本身不属于什么元素。但是浏览器在对待文本内容时,依旧将其看做一种特殊的内联元素,浏览器会计算其对应的间距等。
我觉的,这个概念还是很好理解的。你打开word写一个文档,也是类似的顺序,块元素就好比标题,它自占一行(当然,不要说标题很长占多行那种例外),写完标题之后,你会手动输入一个enter来换行。而内联元素就是普通的文字,你只管打字,它满一行了,它会自动换成到下一行了。
流的概念,很简单。就是从上到下(块元素),从左到右(内联元素,如果这一行满了,自动换行到下一行去接着排)。不过它很重要,流(Flow)概念和盒子模型(Box Model)是理解布局的基础。
按照流的概念来显示html文档,自然没办法满足各种五花八门的需求,所以我们就需要通过css来进行定位布局。
当然,主要是通过position来进行布局。
position属性具体值如下。
inherit属于继承,连IE8都不支持,所以不具体讨论,我们讨论前四种。同时position属性适用于任何元素,当对内联元素也设置position时,就相当于也同时设置了它们的 display:block了。
一,static(静态定位)。
静态布局,就是按照标准流模型来布局,从上到下,从左到右。这也是position默认的布局方式。对静态布局设置位置属性(left,right,top,bottom)没意义。
而我们可以通过float(浮动)来改变这种默认布局。
float:left|right|none|inherit
还是上代码,看效果,来具体讨论吧。。
html代码
<footer><p>我是footer的内容</p></footer> <div class="box1">box1</div> <div class="box2">box2</div> <div class="left_content">---测试文字省略。。。。。。------</div> <div class="box4">box4</div>
CSS代码
body{ margin: 5px; } footer, div{ margin: 10px; padding: 0px; } .box1{ float: right; } .box2{ float:right; }
效果:
所谓float(浮动),就是说,通过这个属性,让该元素脱离了标准流,来让这个元素在水平方向靠近某一个方向。(虽然只能是左或者右)。在标准流当中,就相当于不存在这个元素了。浮动元素也不会占据正常流的空间。所以排在该元素下面的元素,自然的就接着标准流排列。算是补上了设置float的元素的空间,从另一个角度来理解,如果正常流在z轴上,z=0,那么浮动元素,z=1。
结合简单demo代码和效果图,有几点需要注意。
1,既然float是在水平方向(x轴)方向,向左或者向右朝浏览器边缘靠近,所以说他是X轴的移动,那么竖直方向(Y轴)呢?Y轴的位置是不变的。结合效果图,box1在footer下面,我们设置box1,float:right,所以box1,就是Y轴不变,漂浮到右边去了。(先忽略同样设置了float:right 的box2)而left_content的文字区域。本来在box1的下面,那么现在box1脱离了自然流,所以left_content自然而然的在标准流中向上走。填充在了本来box1所在的位置。所以说,box1和left_content的Y轴是相同的。
讨论到这里,有人就该说了,你说box1和left_content的Y轴是相同的。你这是瞎吗?通过边框你也能看出来他们的Y轴不相同啊。其实这是一个常见的误区,也是很容易引起bug的地方。在正常流中,两个块元素在上下的margin是会折叠的。并且以大的值为准,所以虽然 footer和left_content都是margin:10px,但是他们上下之间的间距也是10,因为上下margin折叠了。(左右margin才会相加)。而box1浮动了,它脱离了标准流,box1和footer的下方margin不会折叠了。所以footer和box1之间的margin是20,而footer和left_content之间的margin是10。。因此box1再向右浮动时,Y轴是不变的。这是正确的理解。只不过牵扯到margin之类的,需要重新计算
2,既然标准流相当于z=0,浮动元素相当于z=1,那么就相当于 浮动元素会遮挡住 它后面的标准流的内容。可是效果图可以看出,文字并没有被两个浮动元素(box1,box2)所遮挡,这是因为内联元素,相当于拥有特异功能,它能感知到浮动元素的存在,并且自然的绕过去。所以left_content这个块,在浮动元素的下面,但是因为内联元素的特异功能,所以导致文字没有被遮挡。
3,通过对比浮动元素box1,和正常流元素box4,可以发现,box4很宽,而box1很窄。这是因为块元素默认width:100%,而 对于非替换元素,在设置float后,如果不被明确的设置一个width,那么它会尽可能的窄。所以设置元素float之后,一般都设置一个width。
4,如果说浮动元素的后面,依旧有浮动元素。比如 box1设置float之后,它后面的box2也设置了float之后,那么理解思路依旧是一样的。在box1设置了float:right,所以脱离了标准流,Y轴不变,浮到右边去了,而它后面的box2,在标准流中自然的补上去,到原来box1的位置,而box2发现自己也被设置了float:right之后,那么它也脱离了标准流,(相当于z=1),Y轴不变,浮动到右边,可是还没浮动到边缘呢,发现前面有个box1挡着了,那box2就排在box1的后面那个位置了。可以想象,如果有box34567依次被同样设置,这一行都挤不下了,那么他们自然的到下一行,继续靠这右边排列。
5,因为浮动元素脱离了标准流,所以它的父元素会感受不到它,因而可能引起父元素的高度很窄,造成坍塌。这个问题就属于清除浮动的内容了。我上一篇的博客有写这个方面,网上大牛的文章更多。
所以整体而言,float(浮动)很好理解。浮动元素先在标准流中排好,然后Y轴不变,X轴向左或者向右,朝着边缘靠近。如果前面正好也有其他浮动元素,那么它就顺序排着就好了。
二:relative(相对定位)
实行了相对布局的元素,先假设其为静态布局,判断出它所应该处于的初始位置,然后通过该元素的位置属性(top,left,right,bottom),在该初始位置的基础上实施偏移。 但是该元素位置偏移了,却依旧的占据着原来的空间。它和静态的float不同,它并没有脱离标准流。
通过一个简单的demo来说明:
html代码:
<footer><p>我是footer的内容</p></footer> <div class="outside_box_wrap"> <div class="insider_box_wrap"> <div class="box1 box_size">box1</div> <div class="box2 box_size">box2</div> <div class="box3 box_size">box3</div> </div> </div> <div class="text_content"> ---测试文字省略。。。。----</div>
css代码:
1 footer, div{ 2 margin: 10px; 3 padding: 0px; 4 } 5 .box1{ 6 padding: 0px; 7 margin: 0px; 8 } 9 .box2{ 10 position: relative; 11 top: 30px; 12 left: -20px; 13 } 14 .outside_box_wrap{ 15 position: relative; 16 left: 50px; 17 top: 100px; 18 right: 200px; 19 } 20 .insider_box_wrap{ 21 position: static; 22 margin-top: 50px; 23 margin-left: 50px; 24 margin-right: 10px; 25 }
效果图:
有几点需要注意:
1,通过 outside_box_wrap 就可以清晰的看出来这个布局的含义了,outside_box_wrap 区域在它原来的位置上以左上角为参考点 偏移了(50, 100)。但是它下面的left_content 文字区域却依旧 没有在标准流中向上补充。那是因为对于 outside_box_wrap 区域,它在static情况下应该所处的那个位置,它即使偏移了,但是确依旧占据着那一片的空间。标准流中的其他元素也无法使用。而同时它的偏移,也对其他元素产生了遮挡效果。
2,参考box2和outside_box_wrap可以看出,位置属性是可以设置负值的。top -10px,是向下偏移-10像素(那其实就是向上偏移10个像素)。
3,这种情况下,(在没有明确设置width和height时),对于top和bottom,如果没有设置值,那么他们就是auto(其实就是0),那么此时,他们就和父元素一样的宽度。如果只有其中一方为auto,那么这一方就取另一方的相反数,而如果top和bottom都有具体值呢,那么bottom就取top得相反数。通过 outside_box_wrap 也能看出来,outside_box_wrap的右边都超出了浏览器的宽度了。所以默认情况下,设置了relative的元素,宽度都是100%。
4,对于left和right来讲,和top,bottom的计算方式差不多, 不过不同的是哪个方向优先级更高,取决于页面所使用的语言,对于绝大部分从左向右读的语言(比如英语汉语),left优先级高,而对于从右向左读的阿拉伯语,right优先级高。
三,absolute(绝对定位)
绝对定位的元素,也是通过设置位置属性(left,top,right,bottom)来实施的位置,不过与relative不同的是,绝对定位脱离了标准流,所以它不再占用标准流的空间了。而他偏移的参考位置,是包裹它的(离它最近的)设置了absolute或fixed或relative属性的祖先元素。如果找不到满足条件的。那就以整个当前页面就是参考。(这种情况其实就是以html,body来作为参考元素了)。
通过简单demo来说明。
html代码。
1 <footer><p>我是footer的内容</p></footer> 2 <div class="outside_box_wrap"> 3 <div class="insider_box_wrap"> 4 <div class="box1 box_size">box1</div> 5 <div class="box2 box_size">box2</div> 6 <div class="box3 box_size">box3</div> 7 </div> 8 </div> 9 <div class="text_content"> ---测试文字省略......-----</div> 10 <div class="box4 box_size">box4</div>
css代码。
1 footer, div{ 2 margin: 10px; 3 padding: 0px; 4 } 5 .box1{ 6 position: absolute; 7 padding: 0px; 8 margin: 0px; 9 } 10 .box2{ 11 position: absolute; 12 top: 30px; 13 left: -20px; 14 } 15 .outside_box_wrap{ 16 position: absolute; 17 left: 50px; 18 top: 100px; 19 right: 200px; 20 } 21 .insider_box_wrap{ 22 position: static; 23 margin-top: 50px; 24 margin-left: 50px; 25 margin-right: 10px; 26 }
效果图。
可以看出:
1,outside_box_wrap 设置了absolute,但是他没有祖先元素设置了position的属性为 absolute或fixed或relative,所以他就是以整个页面来作为参考点设置(50, 150)坐标的。而对于 设置绝对定位的 box2来讲,它的参考位置是outside_box_wrap。而不是他的直接父元素 insider_box_wrap(同时也是 outside_box_wrap的子元素)。
2,注意到 我们对 outside_box_wrap 设置了left和right,它的宽度设置并不像relative那样,right取相反数,而把宽度设置了100%,这说明,针对绝对定位,left,right,top,bottom。在未明确设置width或height情况下,是同时生效的。而如果明显设置了width,或者height,四个位置属性的优先级就变成了 top>bottom,left>right(针对英语等从左往右读的语音),right>left(针对阿拉伯语等从右向左读的语言)。
3,四个位置属性设置负值同样起效果。
4,需要注意是box1的位置。它设置了absolute,但是并没有设置top,left,right,bottom中的任何一个。而他的左上角是和 insider_box_wrap的左上角重叠。这是因为 insider_box_wrap 包裹了它,它就默认处在它最左上角的位置了。(我觉的这是一个比较有意思的现象)。
四,fixed(固定定位)
fixed其实只是一种特殊的absolute定位。差别在于absolute的参考位置是 position不是static的祖先元素。而fixed参考位置则是浏览器窗口。也就是说 固定定位的元素并不是随着滚动页面而消失,它就一直在浏览器窗口的某个固定位置。其余的就和absolute一样。。这种定位最常用的是 页面设置了优惠券区域,固定页眉,页脚之类的。因为和上一个absolute很相似,所以就不再演示demo了。
另外,对于因为各种定位产生的遮挡问题,css有一个属性叫做z-index,用来设置元素的堆叠顺序。其实就是Z轴。垂直于屏幕所在的平面,朝向用户的一面为正,背面为负。所以z-index同样可以为正为负。而默认的定位时,元素z-index=0的。z-index只有postion不是默认static的元素才会生效。
以上内容就是本人关于css中定位的理解了。如果理解肤浅或错误的地方,欢迎指点批评。
-------
作者: www.yaoxiaowen.com
github: https://github.com/yaowen369