有两种流行的css定位的方法:浮动或者绝对定位。这两种类似的方法都有他们的优点和缺点。我和我的团队伙伴们开发了一种全新的定位的方法,这也许是世界上最好的方法。经过了一些实验和测试之后,现在是时候把它和业界一起分享了,来看看我们是如何一起工作,并改进。
我称呼这种方法为:“伪绝对定位”,这是一种伪造的列的技术 什么我们需要另外一种css布局技术 很 多网站都是基于带页头和页尾的分栏来设计。使用绝对定位布局,如果在垂直的分栏高度不固定的情况下,几乎是不可能来准确定位到页尾的位置。通过浮动定位,如果有意想不到的内容的出现,会打乱你页面的整体布局(意译),关于这种情况,可以查看Shaun Inman in Clearance的描述。这些问题由于ie的宽度解析问题,都是非常讨厌,且难以解决的。
我们遇到的情况相当的复杂:我团队试图开发一个基于 WYSIWYG(所见即所得)的表单,而且可以允许用户把内容在界面上随意的拖动。我们需要建立一个精巧的结构让用户不需要过度的倚赖静态布局,而且在他们的需要的时候把相应的列可以对齐。
例如:假定我们需要在表单的同一行里面加入邮编和城市选项,这两者在内容逻辑上是在同一行的。
为了实现它,我们尝试用 Holy Grail technique所 创造的浮动定位方法。通过这种方法,我们需要去调整邮编对象width,border,margins,或者padding来和城市选项对齐成一行。这是个很麻烦的事情,因为邮编的宽度是动态的。或者我们调整了邮编之间的空白之后,城市的位置可能就挪位了。页面里面更多的元素,栅格中的布局,都需要做这种 无聊而且单调的调整。另外,微小的(属性的)数字变化就会导致布局错乱过敏。所以他基本上不可能用于弹性布局中。
然后我们试图利用绝对定位。他可以给我们更多的在位置上的可控性,而且他很健壮。但是绝对定位元素没有高度,这会导致父层元素的塌陷(其实是因为定义了position:absolute 之后,对象会脱离当前文本流,而父层元素任然处于文本流之中,所以在浏览器渲染的时候,是不会计算绝对定位元素的高度的,并非作者所说的have no height)。所以这样很难在不把所有的元素都绝对定位的情况下来对内容定位.所以这个方法在动态布局中基本不能实现。
另外一种办法
最后,我们的解决办法基于从定位过的布局中计算右侧的距离,而不是从在他源码前的元素右侧来计算他(?)。我们通过 position: relative, left: 100%和负margin值的组合来实现。 我们的方法从建立栅格和单元开始。我们可以在容器中把任意多的单元排成一行而且可以有任意多行。
<div id=”canvas”>
<div class=”line”>
<div class=”item” id=”item1″>
<div class=”sap-content”>content here</div>
</div>
</div>
</div>
基类的css如下:
.line {
float: left;
width: 100%;
display: block;
position: relative;
}
.item {
position: relative;
float: left;
left: 100%;
}
对于特定的单元。我们只需要给他负margin-left值以及指定宽度即可。
#item1 {
margin-left: -100%;
width: 30%;
}
基类的css将每一个单元的都在容器的右边定位在容器的右边,每个单元的宽度都倚赖于他自己里面的内容,而且所有单元都按照html源码的顺序排列。margin-left现在是为了抵消容器右边的距离,而不是左侧。
注:作者的解释比较简单,以下是我的分析:
首先有一个外容器,id=”canvas”来包含列,也就是栅格中的一行。 canvas用来定义你所需要的宽度。需要有overflow:hidden;(用来计算内容item里面的float元素所带来的高度,同时解决等高列问题)。其中每一行定义为line,我们这里假设他宽度为950px
.line {
float: left;(计算内容item里面的float元素所带来的高度)
width: 100%;
display: block;(float之后自动具有block,是不需要的)
position: relative;
}
line:position: relative;之后,所有列元素,也就是item都将基于canvas的左上角为定位元坐标。里面每一块内容叫:item
.item {
position: relative;
float: left;
left: 100%;
}
left: 100%;将每个item的定位坐标初始化为line的最右侧; float和position: relative;的作用:float让他脱离文本流,position可以去控制iteam的位置。 定位采用margin-left的负值来定位。
请注意,item的初始坐标都是line的最右侧。我们从左往右依次在源码中排列item,我们将他们标识为:item1, item2,item3.宽度分别为:180px,500px,250px(item与item间隔10px) 。
那么最左侧的item1,margin-left=-100%,也就是整个line的宽度。
· item2,margin-left:950-180-10=760px,请注意是负值
· item3,margin-left:950-180-500-10-10=250
这样我们完成了一个典型的淘宝三栏布局。
优点
通过这种伪绝对定位。我们可以将任何单元在预先定义好的栅格中排列。所有的单元只需要简单的浮动,多亏有了clear,可以有和普通文档流一样的优 点。栅格 中的每一行的高度或者依赖于其中的内容,或者被css所定义,无论定义了多少列,每一行都是100%的宽度。而且我们可以避免使用笨拙的正值的 margin或者padding来调整元素间的空白。这些技巧都不需要因为ie6的盒模型错误导致所需要的css hack。
这个技术另外一个优点是很大程度上减轻了脆弱的浮动。当浮动盒模型的内容的宽度大于盒模型本身时,它将把下一个盒对象推到右边(通常情况下,这个盒对象会落到下方)。
通过伪绝对定位,该盒模型将无论如何都保持在原位,而盒模型中的内容,可能会重叠到一起,这依赖于是否overflow:hidden。现象谨此而已,而且根据我们的观察,内容发生重叠比破坏布局要好得多。
坦白的说,我对这项技术的结果非常满意。它合理的利用了被广泛在浏览器中所应用的的HTML 4.01 , CSS 2.1 ,负值margin。
它有更多的好处:
· 它可以工作在流体设计下;
· 他可以与等高列(equal height columns )很好的结合起来(尽管他是一个已经被解决了的问题);
· 他可以很好的结合等宽布局(fixed-width)或者活动宽度(flexible-width)列。
· 甚至可以递归的使用这种布局结构。例如将单元作为新行或单元的容器
缺点
伪绝对定位布局非常具有创造力,天生为栅格布局设计而出现。而且越是复杂的结构越值得这样去做。如果你只需要实现2列定宽设计,这项技术也许不是那么值得。
另外,伪绝对定位布局也不是适用于所有的情况。如果你需要把元素左对齐,那么你使用的单元与那种父容器指定宽度的单元将会不一样,因为你无法计算 offset。例如:如果父容器宽度是800px,里面的单元与右侧要间隔2em,那么你无法计算margin-left的负值,因为你不知道800px 是多少em
而且它只是一项新技术,并没有被成千上万的人测试过。所以它如仍然是实验性的。所以在你实际的markup,css和浏览中,也许会出现你无法预料的情况。
剩下的一点是:如果有一个元素,它的父容器小于在排列比在html源码中靠前的那个元素,在同一行中的后续的元素将会被推到右侧,距离等于第一个元素和父容器宽度之差。