CSS 相对|绝对(relative/absolute)定位系列(一)
一、有话要说
以前写内容基本上都是:眼睛一亮——哟呵,这个不错,写!然后去古人所说的茅房里蹲会儿,就有写作的思路了。但是,构思相对/绝对(relative
/absolute
)定位系列却有好些时日,考虑到:
1、 琐碎的俗称tip的东西不少,如何寻找主线串联;
2、 不少自己“非主流”的破常规的观点,如何一句话提炼,如何清晰表述,如何让人易于理解;
3、 relative
/absolute
/z-index
本身关系暧昧非比寻常,如何有重点的叙述,同时又不扯断他们之间的牵连;
4、 又要拿一些大网站说事,如何避免可能的无意的言语上的冒犯;
5、 想一个够淡定同时又很噱头的题目;//zxx:此项以失败告终
6、 等等……
现在,终于决定开始敲键盘了,长时间的酝酿使得现在胸中有千言万语想倾吐啊,不急,像《火影》《海贼王》一样,是个长篇,娓娓道来。
二、必要的题外话
题外话说两点内容,一是关于观点与言论,二是关于情感化思维。
观点与言论
有句话貌似是这么说的:“我坚决不同意你的观点,但是我誓死捍卫你说话的权利!”;前段时间回家,在闲聊子女教育问题上(我纯听众),小舅就反复强调他的观点:“你可以义正言辞的当面孩子说:‘你的这种做法我认为是错误的!’,但是,你不能强制他按照你的想法来做。”
技术的道路上,似乎有这么个流程:经验 → 观点 → 世界观。 很多有经验的开发人员心中(可能无意识的)就形成了一套自己的准则,亦称技术方面的世界观。这种世界观本质上是带有宗教信仰的气息的,于是,当相悖的言论、相悖的世界观出现的时候,如果其不是海纳百川版包容与谦逊,所谓不屑,口水仗就会随之出现。
有着自己的世界观本身是好的,但是,如果像清朝政府一样,自我感觉良好,闭关锁国,对外在事物过分敌对,对自身也是一种限制,难有大成。所以,应该时时刻刻保持谦逊,虚怀若谷地思考接受别人的观点,方能在技术飞道路上不断前行,突破一个又一个的瓶颈。这也是我自己经常提醒自己的。
这里,我是非常欢迎各同行发表您的不同观点与看法的,尤其有理有据,争锋相对的观点,因为这让我看到了进步的可能点。为了帮助阐述自己的观点,本系列中会反复拿国内的一些大网站说事。我认为发表观点的权利应该是自由的,我可以很直接毫不掩饰地说:“我认为你这里的做法是欠妥的,可以改进的!”,这里我仅仅是从我个人的角度,以我的世界观来表达我的观点,仅仅是表达,完全没有什么嘲笑、不屑的意思,因为我知道,本身就没有什么对错之分,或许只是大家的出发点,侧重点不同而已。优秀的同行往往反而乐于见到真知灼见的观点,但是,林子大了,什么样的鸟都有,有些一直自以为是的人往往会自认为自己小小的自尊被侵犯而恶语相加,或是报以鄙视与嘲讽。要知道,在山顶上的人和山脚下的人眼中,对方都是渺小的;笑是会传染的,你在笑别人的时候也在被别人笑着;自以为在看画中人,其实自己也被当作画中人看着。
文章这东西就跟艺人一样,要有特色,好比苏打绿的娘娘声,春哥的爷们声。尤其是论述观点的文章,显然就要像辩论赛一样,观点鲜明,言辞激烈,否则,大家宁可去看凤姐说英语也不会鸟你写些什么东西的。
情感化思维
我在年初的“CSS float浮动的深入研究、详解及拓展(一)”一文中的引言部分曾阐述过“情感化思维”,认为“代码的情感化思维从无意识到前意识到意识”“代码的情感化认识渗透着部分人格”,您要是有兴趣可以去原文查看,这里再补充点我的新认识,情感化思维接近于感性思维,主要有感情倾向和形象化思维组成。这不难理解,举个2年之后的例子,假设那时我有女朋友了,并同时假设名叫婉儿,然后同事问婉儿,你对小张的情感是?婉儿的回答就会使“喜欢”,这就是“感情倾向”;然后同事又问,小张在你心中形象是?婉儿的回答是“冬日里的阳光,温暖的避风港”,这就是形象化思维。
例如浮动(一)中提到的我对浮动的感性化的认识:浮动就是一个变态,魔鬼,自私自利且影响他人的混球。我讨厌浮动。
其中,“变态,魔鬼,自私自利且影响他人的混球”属于形象化思维,“讨厌浮动”就属于感情倾向,合起来就是情感化思维。
我到现在还不清楚,是不是其他人跟我一样,会很感性的,夹杂着强烈的个人情感和性格特质去看到CSS的一些属性的。就自己而言,这种情感化的认识有助于理解与使用CSS。所以,本文也将借助情感化思维分析“position:relative
/absolute
”属性的脾气特性,利弊好坏。
三、absolute属性的情感化认识
我对position:absolute
属性感性化的认识:absolute
是一个善良的有个性的,我行我素、喜欢凌驾一切之上的魔鬼。这家伙,不喜欢也算不上讨厌,但是知道没事最好少招惹,免有后患。
四、position:absolute与float:left是近亲
先给大家讲个故事吧。曾经有两个魔鬼兄弟,一个叫浮动,一个叫绝对定位,它们总是一起在空中飞行戏耍的。但是,不幸的是,有一天,浮动被巨雷击中,双翼折损,陨落凡间,好在性命还在,但是,翅膀不在,它只能永远留在凡间,与芸芸众生呆在一起。偶然一天,众生发现浮动有一种能力,可以让布局整齐,有方向性的排列,于是,大肆使用其能力,建房子,造家园。但是,浮动本质上是魔鬼,其破坏性经常让房子高度塌陷,而饱受众生诟病。可怜的浮动啊,原本出身的意义就不是来建房子的,却被众人误解与指责。浮动的兄弟绝对定位本应在天空翱翔,但是为了看望其兄弟,也经常去凡间看望。后来,人们发现,绝对定位也有布局建房子的能力,也想拿来使用。但是,绝对定位不同于浮动,其翅膀尚在,其一个不乐意就可以飞回天空。聪明而狡黠的人们发现了一个可以限制绝对定位的物体,名叫相对定位。于是,什么时候,人们想利用绝对定位建房子,就使用这个名叫相对定位的东西把他限定住。后来,有一天,人们忍不住心中的疑问,就问绝对定位:“你在天上好好的,为什么没事要下来受罪呢?”绝对定位长吁一口气,道出了浮动就是他那可怜的弟弟的事情。“不会吧!”人们很惊讶,“你们样貌差异这么大,跟志玲姐和凤姐之间的差异有得一拼呢!”“唉”绝对定位又是一声叹气,“被雷击,翅膀没了,还毁了容,于是……”绝对定位忍不住抽泣起来。后来,人们逐渐明白,原来绝对定位下凡间帮着建房子都是自愿的。果然,后来,一部分人试着不再使用叫做相对定位的东西限制绝对定位,绝对定位也没有飞向天空……(未完,待续)
故事先说到这儿,正如故事里提到的,position:absolute
与float:left
论长相差别有志玲姐和凤姐那么大,但是,却是近亲,细想一下也合情合理,两者有两大共性:包裹性,破坏性。
包裹性
包裹性换种说法就是让元素inline-block
化,例如一个div
标签默认宽度是100%
显示的,但是一旦被absolute
属性缠上,则100%
默认宽度就会变成自适应内部元素的宽度。哦,举个例子吧,如下测试代码:
CSS部分:
.div { padding:20px; margin-bottom:10px; background-color:#f0f3f9; } .abs { position:absolute; }
HTML部分:
<div class="div"> <img src="mm1.jpg" /> <p>无absolute</p> </div> <div class="div abs"> <img src="mm1.jpg" /> <p>absolute后</p> </div>
结果如下图所示:
您可以狠狠地点击这里:absolute的inline-block化demo
float
也是典型的inline-block
化元素,这种元素的inline-block
化适用于任何水平的标签。例如平时我们要让span
标签支持width
属性,可能要设置:
span { display:block; width:100px; }
但是,有float:left
/position:absolute
撑腰的情况下,display
属性就是多余的,可以直接回家喝茶了。
span { float:left; width:100px; }
span { position:absolute; width:100px; }
破坏性
论破坏的功力,绝对定位显然比浮动更甚一筹,但是人们诟病的更多的却是浮动的破坏性。这不难理解,整天在耳边飞来飞去的苍蝇要比不常见的吸血牛虻讨厌。众人已经把浮动当作凡人中的一份子,而对于绝对定位,人们知道,毕竟人家原本隶属天上,能下凡间来帮忙造房子已经不错了,没有必要去苛求指责人家。
浮动的破坏性在于切断line box链,致使高度塌陷,但由于浮动元素仍在凡间(DOM tree),实体是看得见摸得着的,所以其占据的实体位置还是在的。而absolute
绝对定位不仅让高度塌陷,又由于从未深入凡间,在凡间没有他的实体位置,所以宽度也是塌陷的。
由于浮动身处凡间,所以其造成的破坏是可以通过其他手段弥补的;但是,绝对定位不属于凡间,其破坏无法修复,因为一是孤独,无人帮忙;二是只有空气,怎能修补。
例如下面的测试:
CSS代码:
.div { padding:20px; margin:10px 0 0 10px; background-color:#f0f3f9; float:left; } .abs { position:absolute; }
HTML如下:
<div class="div"> <img src="mm1.jpg" /> <p>图片无absolute</p> </div> <div class="div"> <img class="abs" src="mm1.jpg" /> <p>图片absolute后</p> </div>
结果如下截图:
可以看到,图片应该的position:absolute
属性后,父标签的高宽都塌陷了,连它的兄弟float
都救不了。
您可以狠狠地点击这里:absolute的破坏性demo
五、position:absolute滥用
在我看来,很多网站,position:absolute
都有滥用的嫌疑,不仅仅是position:absolute
滥用,其left
, top
属性值也滥用,relative
属性值滥用,z-index
也滥用。有的属性滥用就是单纯的多些代码而已;而有些其实可以不使用的地方也使用的话会给后来的扩展和维护造成很大的麻烦的。
relative
/absolute
/left
/top
/z-index
这5个关系紧密,无论将哪一点都会牵扯到其他。为了避免讲述的混乱,我尽量只讲某一个。例如,这里只讲absolute
属性。
absolute
经常被一些新手拿来大肆建房子做布局也是可以理解的,貌似什么时候我看过一篇文章说,absolute
属性的出现本来是想把页面搞得像photoshop那样,一个图层一个图层覆盖似的。但是,页面的发展显然与这个背道而驰,毕竟页面是活的。确实,像photoshop,把一个个层搞出来,使用absolute
属性,以及一定坐标值就可以定位出来了。不需要考虑什么间距啊,margin
啊,一些IE下乱七八糟的bug啊什么的,有一了百了的畅快感。尤其对于页面制作不熟悉的新手,这种绝对定位布局可谓屡试不爽。
还有时候,遇到有些复杂的布局,项目经理又催得紧,懒得再去折腾,干脆,直接,绝对定位,先把效果做出来再说。因为绝对定位毕竟有飞翔的能力,例如想在黄浦江中间建个灯塔,直接告知坐标,飞过去,灯塔一插,搞定了,很省事的。
看上去省事,其实是自掘坟墓。所谓“本属天上人,勿管凡间事”,对于普通的页面布局,不到万不得已不要使用absolute
进行定位。
对普通的layout,如果动不动就使用absolute
属性,我个人是比较深恶痛疾的。
首先自己是个流体布局控,绝对定位这种东西,显然没有流动的气质,尤其拿来定位后(虽然有时候在relative
的庇护下也有一定的流动性)。流动性布局很强调不定宽,不定高,活用标签自身属性,顺其自然,最少干预。但是由于absolute属性(尤其是带有left/top值)的破坏性,会导致高宽塌陷,于是,不得已,需要设定一个高度值(或是足以撑开高度的值),例如新浪微博导航就是绝对定位,于是,导航外标签必须定高,否则,下面的元素会上来发生重叠:
其次,自己是个代码控。自己是个有代码癖的人,眼中是容不得可以不使用的CSS属性的。对于absolute
布局,为了修复其破坏造成的后遗症而花费的CSS代码开销在我看来已经超出的容忍的限制。
最后,也是更重要的,就是绝对定位大大降低了页面的扩展性和维护性。其在降低维护性方面的卓越表现不仅仅在于自身,还在于其领导能力(指引领relative
与z-index
制造更加混乱的页面,这个后面会依次讲到)。我想有经验的页面重构人员都深有体会,去改之前别人写的页面,出现问题的很多时候就是那些不知道为什么要绝对定位的元素,这些元素就像地雷一样,总以为安全,放心大胆地往前走,结果,“砰”一声嗝屁了。覆盖,重叠,精确调距离,修改之前的高宽参数等,想想都让人吐槽。最后,越改越混乱。
absolute
属性本来是个好孩子,可做奇兵,颇有妙用。但是,太多人把天上的凤凰当野鸡养,把absolute
过多的用于普通布局,而沉浸其中,不亦乐乎。
其实想想,要求也不能那么高。毕竟大部分的同行都是做中小站点的,一个页面寿命短短几个月说不定就要抄底重来。花功夫去折腾扩展性,代码量什么的,实在是对不起自己那点可怜的工资,有这点闲功夫还不如去撩撩美女姐姐,泡泡清纯小妹呢。所以,淡定,淡定!
不过,一些结论性的话还是要说的:想重构高质量的页面,少用绝对定位布局!
六、鞋子是用来穿的
又是题外话。对于CSS属性,如何高效地使用它们,如何使页面流畅,灵动,又极具扩展性和可维护性呢?就是该生下来该干嘛的就让他干嘛。就拿绝对定位举例,absolute
最大最能动的空间是在天空中,不受任何限制的天空,可以自由驰骋,又与世隔绝,不会对凡间造成任何侵扰,顶多遮住点阳光。所以,absolute
尽量不要身陷林立的DOM中,尤其是用来做普通的布局,这可真是拿砍刀削指甲,做着危险的活儿啊。
举个更容易理解的例子吧。我们都知道鞋子是用来穿的。但是,它还有其他功能,比如说攻击武器,例如嫌小布什台上讲话语速太快跟不上,听不懂,你就可以掷出你的飞鞋提醒他降低语速。很显然,虽然鞋子有做武器这个特殊功能,你是不会去淘宝上买个百八十双鞋子,专门用来扔人的吧!absolute
属性的使用一个道理。
下集看点
下集内容还是讲absolute
定位,多实例与实践。内容大致有:
普通absolute
布局的替代实现方案;body
标签是absolute
自由的海洋;
解析absolute
元素margin
定位于left
/top
的恩怨情仇;absolute
与reflow
回流及应用;
等……
w3school过了HTML的知识之后,觉得要自己单纯地去啃知识点有点枯燥,然后自己也很容易忘记,所以便找具体的网站练手便补上不懂的知识点。position:relative和postion:absolute困扰了我快一个星期之久,网上找到的资料鱼龙混杂,刚确定“这样”的理解之后,看另一份资料,发现“这样”理解是错了,就这样不断更正,并记录下来,最终整理出这份,以备参阅。
若有错误,请指正。
下面的结果都是基于firefox38版本来测试的。
position:relative相对定位
1. 如何定位?
每个元素在页面的普通流中会“占有”一个位置,这个位置可以理解为默认值,而相对定位就是将元素偏离元素的默认位置,但普通流中依然保持着原有的默认位置。(在父级节点的content-box区定位,父级节点有文字的话,元素的默认位置则是紧随文字)
2. 不会改变行内元素的display属性。
3. 并没有脱离普通流,只是视觉上发生的偏移。
代码——
<body style='margin:0;padding:0;background:#BDD7EE;color:white;'>
<div class='contain' style='margin:10px;border:10px solid white;width:300px;background:#F8CBAD;padding:10px 0 0 10px;font-size:20px;font-weight:bold;'>
<div class='one' style='width:50px;height:50px;background-color:#FFE699;top:-10px;left:0px;'></div>
<div class='two' style='height:50px;color:#fff;background-color:#C5E0B4;'>position:relative定位测试</div>
</div>
</body>
显示——
给子元素one的style加上position:relative;后显示——
给父级元素contain的style加上文字后显示——
将one由div节点改为span节点,并加入文字“你好”之后显示——
<body style='margin:0;padding:0;background:#BDD7EE;color:white;'>
<div class='contain' style='margin:10px;border:10px solid white;width:300px;background:#F8CBAD;padding:10px 0 0 10px;font-size:20px;font-weight:bold;'>如果父级节点有文字的话...
<span class='one' style='width:50px;height:50px;background-color:#FFE699;position:relative;top:-10px;left:0px;'>你好</span>
<div class='two' style='height:50px;color:#fff;background-color:#C5E0B4;'>position:relative定位测试</div>
</div>
</body>
position:absolute绝对定位
1. 如何定位浮动?
-
设置了TRBL
相对最近的设定了position:relative/absolute的父(祖先)节点的padding-box的区进行定位(忽略文字),找不到符合条件的父(祖先)节点,则相对浏览器窗口进行定位。 -
没有设置了TRBL
则默认浮动,默认浮动在父级节点的content-box区。
2. 不管是块级元素还是行内元素,应用了position:absolute之后,display为block:
-
可以设置width和height
-
没有设置的话,width默认为auto
3. 脱离文档流,容器(父)元素将得不到脱离普通流的子元素高度
代码——
<body style='margin:10px;width:300px;color:white;background-color:#BDD7EE;'>
<div style='background-color:#F8CBAD;padding-top:10px;'>祖先元素
<div style='background-color:#FFE699;border:10px solid white;padding-top:10px;'>父级元素
<div style='background-color:#C5E0B4;'>子元素</div>
</div>
</div>
</body>
显示——
给子元素的style加上position:absolute;top:0px;left:0px;后显示——
给子元素的style加上position:absolute;top:0px;后显示——
注释:应用了position:absolute之后之设置了top,所以子元素的top紧贴浏览器窗口的top(距离为0px),因为没有设置left,所以子元素左边就默认父级元素content-box区的左侧进行定位(没应用position:absolute之前左侧该在哪个位置就在那个位置)
给子元素的style加上position:absolute;后显示——
案例:理解应用了position:absolute的元素没有设置TRBL的话,则默认浮动在父级节点的content-box区
用一句通俗易懂的话来说就是,它该在哪个位置就在哪个位置,只不过不占位而已。
先理解下上面示例代码的显示图,以及给自己元素加上position:absolute后的显示图。
给子元素的样式加上:display:inline;我们看看如果子元素是内联元素的话会如何显示。
假如有两个同级块级元素,看看第一个子元素和第二个子元素分别应用position:absolute后的效果如何。
<div style='background-color:#F8CBAD;padding-top:10px;'>祖先元素
<div style='background-color:#FFE699;border:10px solid white;padding-top:10px;'>父级元素
<div style='background-color:#62C292;'>子元素(上)</div>
<div style='background-color:#C5E0B4;'>子元素(下)</div>
</div>
</div>
如果这两个同级块级元素都应用了position:absolute;这两个元素会进行重叠,子元素(下)显示在前面,那是因为默认代码靠后的元素的z-index比较大。
上面的案例中,将第二个子级元素换为内联元素,子元素(下)的起点位置并没有改变。
试试给代码中的第一个元素的style加上display:inline;看看上面的子元素是内联元素的话会如何显示。
<div style='background-color:#F8CBAD;padding-top:10px;'>祖先元素
<div style='background-color:#FFE699;border:10px solid white;padding-top:10px;'>父级元素
<div style='background-color:#62C292;display:inline;'>子元素(上)</div>
<div style='background-color:#C5E0B4;'>子元素(下)</div>
</div>
</div>
现在调换下应用position:absolute的位置
代码:
<div style='background-color:#F8CBAD;padding-top:10px;'>祖先元素
<div style='background-color:#FFE699;border:10px solid white;padding-top:10px;'>父级元素
<div style='background-color:#C5E0B4;'>子元素(上)</div>
<div style='background-color:#62C292;'>子元素(下)</div>
</div>
</div>
第一个子元素是内联元素的话——
<div style='background-color:#F8CBAD;padding-top:10px;'>祖先元素
<div style='background-color:#FFE699;border:10px solid white;padding-top:10px;'>父级元素
<div style='background-color:#C5E0B4;display:inline;'>子元素(上)</div>
<div style='background-color:#62C292;'>子元素(下)</div>
</div>
</div>
综上:不管是块级元素还是内联元素应用position:absolute并且不设置TRBL,它都会默认在父级元素的content-box区浮动。原来的起点位置也是应用绝对定位后的起点位置,只不过如果应用了position:absolute的内联元素左边也有内联元素的话,它的起点位置会变得更靠前,直到紧挨左边内联元素的边界。
综合案例:看看position:relative和position:absolute的综合效果
沿用position:absolute的案例代码——
<body style='margin:10px;width:300px;color:white;background-color:#BDD7EE;'>
<div style='background-color:#F8CBAD;padding-top:10px;'>祖先元素
<div style='background-color:#FFE699;border:10px solid white;padding-top:10px;'>父级元素
<div style='background-color:#C5E0B4;'>子元素</div>
</div>
</div>
</body>
在上面代码的基础上分别应用以下的定位后看看效果,并理解。
案例诊断:
-
给祖先div加上"position:relative;"以及给子元素加上
"position:absolute;top:0px;left:0px;"
-
给父级div加上"position:relative;"以及给子元素加上
"position:absolute;top:0px;left:0px;"
-
给祖先和父级div加上"position:relative;"以及给子元素加上
"position:absolute;top:0px;left:0px;"
-
给祖先div加上"position:absolute;"以及给子元素加上
"position:absolute;top:0px;left:0px;"
-
给父级div加上"position:absolute;"以及给子元素加上
"position:absolute;top:0px;left:0px;"
-
给祖先和父级div加上"position:absolute;"以及给子元素加上
"position:absolute;top:0px;left:0px;"
应用:消除环绕浮动元素的影响
父级,position:relative(不设TRBL)
子级,第一个div的float:left;第二个div的position:absolute(不设TRBL)
因为第二个子级div元素默认会在父级元素的content-box区浮动,它可以消除上一个同级子级div元素的环绕浮动影响。
案例代码——
<div class='contain' style='margin:10px;width:300px;background:#F8CBAD;padding:10px 0 10px;color:white;'>
<div class='one' style='width:30px;height:30px;background-color:#FFE699;float:left;'></div>
<div class='two' style='color:#fff;background-color:#C5E0B4;'>position:absolute消除浮动环绕的影响测试</div>
</div>
显示——
给父级元素加上position:relative,给第二个子级元素加上position:absolute后,显示——
我们看到,确实是消除了环绕浮动元素环绕的影响,position:absolute的优先级高,所以float元素被遮住了,并不是消失了。另外看到contain元素的高度不受子元素的影响了,因为它们都脱离文档流了。
参考颜色
修改记录
-
2016.12.23增补案例理解默认浮动