CSS 相对/绝对(relative/absolute)定位系列(二)

这篇文章发布于 2010年12月26日,星期日,21:09,归类于 css相关。 阅读 102364 次, 今日 69 次

//zxx:直接接上回

一、常见absolute布局的替代实现方案

absolute属性配合left/top/right/bottom属性具有极强的定位性。这种功能特性是如此的明显与强烈,可能会让页面重构人员很单纯的被这一特性“捕获”,而产生迷失。

一板一眼的描述可能难以理解,举个通俗点的例子吧:
一个脸蛋不错身材超好的姑娘穿上超PP的衣服后是如此的光艳动人,对于我们这类常年困居于深宅大院的光棍男来讲,这种美艳是如此的迷人,以至于我们的精力多集中在这沉鱼落雁的美貌上,而忽略了其他一些东西,例如知性,善良,贤惠等。很容易的,我们以后一想到此女子,第一反应就是“美貌”,至于其他,在如此美貌下已经不重要了。

此道理反映在web上就是,我们极易先入为主地认为absolute的价值就是借助left/top属性来进行定位的。说句不严谨的话,目前估计超过90%的普通布局中的absolute属性都是用在定位上了。恩,这个回头再说,这里还是看看一些常见的absolute布局如何通过使用其他属性完成同样的布局效果。既然absolute属性是拿来定位,我们只要使用其他属性定位就可以了。此时,自然而然想到了CSS中另外一个更加低调全能的定位属性margin,下面的前两个例子都是使用margin代替absolute及相关属性。

京东商城首页标价定位
首先拿京东商城首页的一个标价样式举例,见下截图:
京东商城首页要示例部分截图

用小bug一看其code实现,果然是绝对定位+定位属性://zxx:小bug时我对firebug的昵称
firebug查看标价的实现方式

要是我来实现,就不会使用absolute属性,会使用margin实现扩展性容错性更强的布局。

不管怎样,先看对比实现效果,您可以狠狠地点击这里:absolute/margin定位布局对比demo

下图为在IE7浏览器下的上下实现方式对比截图(默认):
absolute/margin 京东商城首页价格定位实现对比截图

可见使用margin,可以实现与absolute布局一样的效果,且CSS属性使用量折半,更为关键的是,布局的扩展性与容错性大大增强了。

在demo页面上的底部有两个测试布局扩展性与容错性的按钮,如下图,第一个按钮是改变标签的宽度,第二个按钮是改变父标签的position属性值为static
demo页面上的测试按钮

我们点击第一个按钮改变dl父标签的宽度后,结果absolute定位的标价已经和图片远离了,而使用margin定位的橙红色背景标价依旧坚挺地呆在原来的位置上,如下图所示:
改变父标签宽度后的布局

点击第二个按钮改变父标签的position属性为static后,结果使用absolute绝对定位的标价没有了束缚,直接跑到浏览器窗口的右下角去了,而margin定位没有丝毫影响(如下图所示,截自Firefox3.6):
static后标价跑到了天涯海角

从上面两个简单的测试可以看出两种实现方式见扩展性和容错性方面的差异。

下面简单讲下相关布局的实现,以下是原来absolute实现的HTML部分代码:

<dl>
    <dt class="p-img">
        <a href="##"><img width="130" height="130" src="http://img10.360buyimg.com/n3/834/11752677-6197-4ffa-b4c0-e66d02640bad.jpg" /></a>
        <div class="p-price">¥999.00</div>
    </dt>
    <dd class="p-name">
        <a href="##">LG  GD580  3G手机 300万像素 999返100元券!</a>
    </dd>
</dl>

类名为”p-price”标签核心样式如下:

.p-price {
   position: absolute;
   bottom: 10px;
   right: 50px;  
   ......

京东商城的实现,中规中矩,想这种带有覆盖效果的定位,使用absolute定位估计是大部分页面重构人员的首选。但是,绝对定位之“绝对”一词本身就意味着其在扩展性方面的表现受限。如果我们要求更高,可以使用CSS代码量更少,扩展性更强的margin布局。

其实现代码如下:
首先HTML部分需要添加一层block水平的标签(其实可以不用加,只要让img外面的a标签block水平显示即可),让标价与图片不会在一个line box中显示,同时将标价外面的div标签改为inline水平元素的标签方便inline-block化,于是,最后的HTML代码如下:

<dl>
    <dt class="p-img">
        <a href="##"><img width="130" height="130" src="http://img10.360buyimg.com/n3/834/11752677-6197-4ffa-b4c0-e66d02640bad.jpg" /></a>
        <div class="new-price-x"><span class="new-price">¥999.00</span></div>
    </dt>
    <dd class="p-name">
        <a href="##">LG  GD580  3G手机 300万像素 999返100元券!</a>
    </dd>
</dl>

相关的核心的CSS代码如下:

.new-price-x {
    margin: -28px 0 0 74px;
}
.new-price {
    display: inline-block;
    ......
}

淘宝首页示例
下面再看另外一个例子,就是淘宝首页的滚动播放效果,使用是absolute定位,通过改变top属性值实现上下的滚动切换,如下图:
淘宝首页absolute实现的幻灯片滚动

实际上,完全可以使用margin-top属性代替这里的relative+absolute+top属性组合。

您可以狠狠地点击这里:淘宝首页margin下的滚动播放demo

使用小bug一看demo页面的定位属性,啊,是margin-top,如下截图所示:
margin属性下的滚动播放

就效果来说,margin-top与绝对定位的切换是一样的,优点在于省了一点点的CSS代码量。但是,相对absolute的动画切换,margin-top值的改变会产生更强的回流(reflow),就性能上而言,要比absolute属性低。

究竟使用哪个,看您自己如何取舍了。

新浪微博示例
最后,拿新浪微博页面的主导航示例。

首先来看看为什么新浪微博的主导航要使用绝对定位。我想主要原因可能是半透明的纯色背景吧。
新浪微博主导航的半透明背景色
IE下filter滤镜

而IE浏览器下药实现opacity效果需要使用filter滤镜,然而opacity属性的半透明效果不仅会影响到当前元素,所有的子元素也会跟着半透明,此时,如果导航内元素放在半透明化的div内部显然容易死翘翘。所以,半透明背景层,与导航内容层不是父子关系,而是兄弟关系,导航内容覆盖于半透明背景上,就避免了导航内容被半透明化的危险。

而覆盖定位一般都离不开absolute属性,所以,新浪微博的主导航使用了绝对定位。然而,这里的绝对定位使用我必须称赞一下,因为很难得的,这里的absolute使用主要是利用了absolute属性的破坏性(高宽占据空间为0的特性),而不是利用其定位性(借助left/top等属性的定位)。

至于这里如何利用absolute属性的破坏性实现自适应的布局,不想讲。有微博的自己用小bug看看,没微博的注册个。

就这里绝对定位的使用来讲,除了莫名的top/right属性外,还是不错的。然而,问题在于这里非要使用绝对定位吗?兼容性的半透明纯色效果非要用并行的两个标签错开重叠定位吗?父子关系不行吗?有句成语叫做“与时俱进”,要是几年前,可能还真得这么搞。但是现在,什么绝对定位啊,重叠啊,计算啊什么乱七八糟的东西完全不需要。就当没有什么半透明效果写,同样可以实现一样的效果。

同样的,关于这里的替代方法,我做了个demo,您可以狠狠地点击这里:新浪微博主导航无absolute实现demo

使用opacity属性或是IE filter半透明滤镜会让子元素跟着半透明。实际上对于半透明的纯色背景,有更佳的实现方法。下面是demo页面的替换实现方法的CSS代码:

.newheader .menu_c {
    background-color: rgba(0, 0, 0, .25);
    filter: progid:DXImageTransform.Microsoft.Gradient(startColorStr=#40000000,endColorStr=#40000000);
}

现代浏览器使用CSS3 rgba实现半透明背景色,IE浏览器使用渐变滤镜实现半透明。

HTML方面,原来的绝对定位的半透明div层直接删掉,此时相关的relative属性等也可以一并去掉。HTML结构变得简单有层次,维护也更加方便了。

关于实现兼容性的半透明背景色,您可以参考我之前的“RGBA颜色与兼容性的半透明背景色”一文。所以具体使用,细节等这里就不多说,下图为前后两种半透明背景实现方式效果对比图:
兼容性半透明背景色实现对比效果截图

二、absolute可以一个人战斗

如果在CSS的世界中没有left/top/right/bottom属性,absolute的潜力估计会挖得深得多。

我们需要意识到,一个应用的position:absolute的元素,其实就只是个非常普通的元素,我感觉与应用了float:left的差异仅仅在于宽度的缺失。为说明此观点,我做了个很简单的demo.

您可以狠狠地点击这里:absolute元素只是个普通的货demo

此demo默认如下图,可以看到浮动的高度缺失造成的塌陷:
demo默认效果

点击示意的按钮后,可以发现图片还是那个图片,还在那个位置,还是那么的安静与优雅。唯一变化的就是文字们有的跑到它的下面了(宽度缺失)。
absolute元素宽度亦缺失

由此可见,absolute属性只是个很普通的属性,跟float:left是个近亲。一个是陨落凡间的恶魔,一个是天空中的恶魔。所以,很多时候,我们在普通布局中使用absolute时候,只要设置position:absolute就可以了,至于left/top之类的都是浮云,定位什么的就当作普通元素,使用margin定位一样有着刮目的表现的。

三、absolute与left/top等属性之间的关系

单纯应用了absolute属性的元素就是个普通元素,跟变身前的美少女战士一样。left/top等属性是具有变身性质的东西,是恶魔absolute元素的翅膀。absolute元素一旦应用了left/top等属性,就具有了飞翔的能力,奔向天空自由驰骋,如果没有relative属性的限制,其会一直飞到天空的边缘(浏览器窗口),并且具有非常明确的方向性。

absolute元素添加left/top等属性后

四、body标签是absolute元素自由的天空

来首小诗调节一下吧:
生命成可贵,
爱情价更高。
若为自由故,
两者皆可抛。

知道《美少女战士》吧,知道主人公水冰月(月野兔)吧,因为人家牛叉,所以为了保护地球,保护未来而战斗。知道《火影忍者》吧,你说要是把鸣人就限制在火影村,帮助老太太抓抓猫,帮助欧巴桑照看孩子,能有大成吗?人家是注定要肩负起忍者世界和平的职责的。

同样的,要是把绝对定位属性用在很深的DOM tree中,再用relative限制住。其实就是把鸣人当作看孩子的人使用,虽然用的时候觉得很好用,但是实际上是埋没了绝对定位元素的才能。没有限制,给予足够的自由,广阔的天空才是绝对定位元素大放异彩,拯救人类的舞台。

一般而言,在web页面上,最宽广的天空莫过于body标签,所以,在我看来,把绝对定位元素直接放在body标签下才是王道,才能最大限度的发挥绝对定位元素的才能。举个例子,淘宝首页顶部小横条上的下拉。
淘宝网首页下拉

此下拉就是使用的绝对定位,但是却是深深地嵌入到DOM中的,如下图:
绝对定位元素在深深的DOM中

这种方法的好处在于简单,对于非IE6浏览器直接使用CSS就可以实现效果了。然而,将默认隐藏的绝对定位元素被relative限制在很深的DOM节点中,弊处相当多:首先增加了DOM的复杂度,不利于维护;越深的DOM元素,造成了回流越强;因为父标签需要relative限制,增加了CSS代码的消耗量;隐藏元素头部加载,延迟了页面的呈现速度;每个下拉几乎都要重新定位,其重用性受限。

如果是我,一定会把这些隐藏的绝对定位元素放在在body标签内部,且最底部加载,以提高页面的呈现速度,甚至根本就不加载。此做法就是mtime时光网下拉导航的做法,是推荐的做法。绝对元素的定位不是通过当前触发元素的relative限制,而是在body大环境中,直接通过触发元素的偏移值设定位置,是最直接最高效的做法。

body标签下自由驰骋,这才是绝对定位元素真正应该呆的地方。真正有才华的元素应该放在更大的舞台上,限制在蹩脚的角落里注定要埋没的。我之前写过一个名为”powerFloat“的万能浮动插件,就是希望通过降低使用的学习成本,让大家都把绝对定位元素解放到body标签下。

于是乎,我们不用担心什么层级错乱的破问题,不会再看到密密麻麻错乱的HTML代码。做页面重构的,本来就应该是每天喝喝咖啡,跟美女前台打情骂俏的工作,现在却搞那么辛苦,太不应该了。

absolute元素犹如有翅膀的小鸟,你是把它限制在鸟笼中,还是把它放飞到天空中自由的飞翔?我想,一切不言而喻。

下集看点:
下篇还是关于absolute属性的(relative属性以及z-index还在其后),内容大致有,
absolutereflow回流及应用;
IE6/7下行高与absolute元素间的误会;
IE6/7下haslayout与absolute元素间的误会;
等……

(本篇完)

赞助商推荐(我也要赞助)

想学到点真东西? ×
如果你有1~3年前端开发经验,不妨 ×
想高薪入职阿里? ×
想通过真实互联网项目成长自己? ×


发表评论(目前36 条评论)

  1. 白吟说道:

    一边看着文章里强调轮播图使用margin属性,一边看着右侧广告用绝对定位实现的轮播图,还是挺喜感的。

  2. cyh41说道:

    absolute的不依赖relative方法并不适用于移动端啊

  3. 微风香水说道:

    如果是我,一定会把这些隐藏的绝对定位元素放在在body标签内部,且最底部加载,以提高页面的呈现速度,甚至根本就不加载。此做法就是mtime时光网下拉导航的做法,是推荐的做法。绝对元素的定位不是通过当前触发元素的relative限制,而是在body大环境中,直接通过触发元素的偏移值设定位置,是最直接最高效的做法。

    引用博主的这段话,希望博主能够给大家展示一个例子好吗?多谢啦~很喜欢看您的博文~学习不少东西

  4. hheedat说道:

    现在想法变了没

  5. Jesse说道:

    定位在body里,那不是lef,top根据网页左上角来确定的了,不是更麻烦了,如果我只想把绝对定位元素放到某个元素的旁边

  6. sean说道:

    jd那个例子 我觉得不是 position的问题,关键是 .p-price的parent p-img没有设 width, 只要把p-img设定一个width就没问题了

  7. yan说道:

    楼主分享的不错。不过CSS3 rgba实现半透明背景色,在IE6中颜色出不来,我用的是ietester测试,是这个原因吗?

  8. Qi说道:

    soga 你真行!

  9. 薇薇说道:

    呃~错了~是margin-top,margin-bottom负值是不是无效

  10. 薇薇说道:

    楼主您好,京东的那个demo,价钱的那里,我线下直接用¥999这样写,结果不能实现,margin-top:-30px只能向上去一点点,并不是预期到效果,我想请教楼主的是:块级元素display:inline-block之后,margin-top,margin-bottom是不是就没什么效果了?自己写了demo,但是还是不怎么确定

  11. 火柴说道:

    价格改动这个确实改得漂亮,但淘宝下拉那个例子,如果把定位的元素都放到body里面,个人觉得有点不妥。特别是样式的不可用的时候,结构是否还会完整。如果真想减少下载时间,也可以考虑用js去喷。
    如果把地球比作body,北极熊比作一个absolute,那么北极熊怎么也不可能跑到南极去玩,它还是在北级那块区域内。对于它来说,北极那块儿地方就是它的天空。

    个人看法

  12. 原健航说道:

    真是的,花这么多时间写这些东西有用吗?!
    不得不说,你真是有很多时间可以用来闲扯啊!!!

  13. 水色说道:

    position:absolute而不设置left和top时,left和top还是存在的,只是值会变成auto而已,
    而auto的意思就还是元素相对于实际的relative元素的坐标而已,所以看起来位置没有变化
    而只是脱离了流,其他的非定位元素会在一个流中布局而已。
    你没有真正理解吧????

  14. 翅膀说道:

    很好的思维方式。但是记得在XHTML的嵌套规则里面,DT里面只能嵌套inline。

  15. super说道:

    我认同13楼的观点,对于float和absolute我觉得文章里面说“我感觉与应用了float:left的差异仅仅在于宽度的缺失”,可是事实上的缺失还是很高的,absolute直接把DOM从文档流里面抽出了,而float还是嵌入文档流的。不仅仅是宽度、高度也是缺失的。博主试试IE9再截图下那个例子就明显额。

  16. 男科说道:

    博主很牛 啊 谢谢

  17. 酱油说道:

    博主分析的很到位啊

  18. wordgold说道:

    还有,楼主不觉的应该对页面进行些优化么,网站打开速度很慢啊…

  19. wordgold说道:

    每个人有每个人的写作习惯,我认为代码应该根据实际情况随机应变,不必要强调各种规则,甚至于可以写些不规范的代码,这并无什么不可

  20. 自由人说道:

    我还是喜欢margin,而且我写的那些代码中基本上都是margin

  21. 自由人说道:

    牛人牛人 来学习 呵呵~~

  22. 康康说道:

    关于淘宝网首页顶部导航,放在那里也许是有他的原因的,比如
    1.是为了禁用了CSS的浏览器或者对CSS支持不够统一的手机浏览器,如果直接绝对定位在body开始或者结束就会使上下文关联性变弱甚至混乱,从“玉伯”对淘宝商城首页栏目的col-main,col-sub,col-extra布局就可见一斑,侧重点不同就会导致设计时的差异
    2.规范性和可重用性,首先,不得不承认powerFloat的强大与好用,但是如果淘宝网菜单子项的布局使用了absolute,那么就势必要有javascript的配合,不管是整合在kissy中还是放在页面中,这都无形的增加了一条羁绊。
    但是我还是很支持你的,因为在现在的情况下,能够让自己节省时间的方法才是最好的方法。

  23. 我觉得这个可以学学。。

  24. 丕子说道:

    木木推荐过来看看

  25. 135956说道:

    其它不说,博主您网站首页的那个“进入我的博客”按钮,在ie8下严重不协调。。。长久以来都没修正。

  26. 直觉说道:

    margin容错性高吗?不见得哦

    我觉得用position要比margin来的快,因为很多时候margin并不兼容

  27. simon4545说道:

    关于淘宝那个,现行的浏览器并不会太受这个的影响。而且在大型项目中,分工是很明细的,
    页面颗粒+模块混着一起,今天你在body中加一段,明天我再加一段,样式表又是大家分开管。时间长了对项目的风险远大于这个小小的改动带来的改进

  28. simon4545说道:

    关于那个什么京东商城,用margin方法也是有问题。当图片未加载到时,你的方法设置的价格标签已经跑出窗外了。

  29. 一路说道:

    赞了!站长非常的用心研究这些问题!

  30. hafeyang说道:

    这,这。。。不是张含韵就是美少女。。。。

  31. Zz说道:

    你好。从上往下数第四章图上的一句话“的relative属性为static:”和从上往下数第五张图上面的那句“点击第二个按钮改变父标签的position属性为static后”。我想大概后者是正确的吧。

    多谢分享!

  32. uteer说道:

    太精彩了,正在学习!

  33. Rainbow说道:

    笔者的文章分析很到位,也为我扫清了许多盲区。期待着笔者对 z-index 和相对定位, 绝对定位的纠缠更深入的分析。