深入理解CSS定位中的偏移

前面的话

  CSS 有三种基本的布局机制:普通流、浮动和绝对定位。利用定位,可以准确地定义元素框相对于其正常位置应该出现的位置,或者相对于父元素、另一个元素甚至浏览器窗口本身的位置。但元素究竟如何定位,定位到什么位置,主要依靠 top/right/bottom/left 这四个偏移属性。本文就定位中的偏移做详细介绍

 

position 定位

  值: static | relative | absolute | fixed | inherit

  初始值: static

  应用于: 所有元素

  继承性: 无

  static: 元素框正常生成。块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创建一个或多个行框,置于其父元素中

  relative: 元素框偏移某个距离。元素仍保持其未定位前的形状,它原本所占的空间仍保留

  absolute: 元素框从文档流完全删除,并相对于其包含块定位,包含块可能是文档中的另一个元素或者是初始包含块。元素原先在正常文档流中所占的空间会关闭,就好像该元素原来不存在一样。元素定位后生成一个块级框,而不论原来它在正常流中生成何种类型的框

  fixed: 元素框的表现类似于将 position 设置为 absolute,不过其包含块是视窗本身

  [注意] 相对定位实际上被看作普通流定位模型的一部分,因为元素的位置相对于它在普通流中的位置

包含块

【1】根元素

  根元素 HTML 的包含块 (也称为初始包含块) 是一个视窗大小的矩形,即 HTML 的父级 document

【2】非根元素

  如果 position 值是 relative 或 static,包含块由最近的块级框、表单元格或行内祖先框的内容边界构成

  如果 position 值是 absolute,包含块设置为最近的 position 值不是 static 的祖先元素 (可以是任何类型),过程如下:

  [1] 如果这个祖先是块级元素,包含块则设置为该元素的内边距边界。换句话说,就是由边框界定的区域

  [2] 如果这个祖先是行内元素,包含块则设置为该祖先元素的内容边界

  [3] 如果没有祖先,元素的包含块定义为初始包含块,即 document

  [注意] 由于元素可以定位到其包含块的外面。这与浮动元素使用负外边距浮动到其父元素内容区外面很类似。所以这里包含块实际上应该是定位上下文,或者定位父级

 

偏移属性

  三种定位机制使用了 4 个属性来描述定位元素各边相对于其包含块的偏移。这 4 个属性被称为偏移属性。

  top/right/bottom/left

  值: <length> | <percentage> | auto | inherit

  初始值: auto

  应用于: 定位元素 (也就是 position 值不是 static 的元素)

  继承性: 无

  百分数: 对于 top 和 bottom,相对于包含块的 clientHeight;对于 right 和 left,相对于包含块的 clientWidth

  这些属性描述了距离包含块最近边的偏移。top 描述了定位元素上外边界离其包含块的顶端有多远。如果 top 为正值,会把定位元素的上外边距边界下移,若为负值,则会把定位元素的上外边距移到其包含块的顶端之上。类似地,left 描述了定位元素的左外边距边界在其包含块左边界右边 (正值) 或左边 (负值) 有多远。如果是正值,会把定位元素的外边距边界移到包含块左边界右边,而负值则将其移到包含块左边界左边。所以,正值会导致向内偏移,使边界朝着包含块的中心移动,而负值会导致向外偏移。

  偏移定位元素的外边距边界时,带来的影响是元素的所有一切 (包含外边距、边框、内边距和内容) 都会在定位的过程中移动

  [ 注意] 定位元素的边界是指定位元素 margin 外侧的边界;包含块的包含区域是指包含块的 border 内侧的 padding+content 区域

绝对定位

  元素绝对定位时,会从文档流中完全删除。然后相对于其包含块定位,其边界根据偏移属性 (top、left 等) 放置。定位元素不会流入其他元素的内容,反之亦然。元素绝对定位时,会为其后代元素建立一个包含块

  [注意] 如果文档可滚动,绝对定位元素会随着它滚动,因为元素最终会相对于正常流的某一部分定位

  当元素绝对定位时,偏移属性表现如下:

    left:0 元素的左边界 (margin-left 外侧) 位于包含块的左边界内侧(border-left 内侧 )
    top:0 元素的上边界 (margin-rop 外侧) 位于包含块的上边界内侧(border-top 内侧 )
    right:0 元素的右边界 (margin-right 外侧) 位于包含块的右边界内侧(border-right 内侧 )
    bottom:0 元素的下边界 (margin-bottom 外侧) 位于包含块的下边界内侧(border-bottom 内侧 )
    当 top、right、bottom、left 四个值都为 auto 时 (即都处于默认状态时),
    left:auto 元素的左边界位于元素处于静态位置时的左边界
    top:auto 元素的上边界位于元素处于静态位置时的上边界
    right:auto 元素的右边界位于正好能包裹住元素的横向区域的右边界 (margin-right 外侧 )
    bottom:auto 元素的下边界位于正好能包裹住元素的纵向区域的下边界 (margin-bottom 外侧 )

  [注意] 元素的静态位置是指元素在正常流中原本的位置,更确切的讲,顶端的静态位置是从包含块的上边界到假想框的上外边距边界之间的距离。假想框是假设元素 position 属性为 static 时元素的第一个框。如果这个假想框在包含块的上面,则这个值为负

//DEMO 中,包含块的 width 和 height 都是 180px,padding 为 10px,所以包含块的 clientWidth 和 clientHeight 都是 200px

格式化

  对于普通流的元素来说,水平格式化的 7 大属性是 margin-left、border-left、padding-left、width、padding-right、border-right、margin-right7 个属性的值加在一起必须是元素包含块的宽度,这往往是块元素的父元素的 width 值 (因为块级元素的父级元素几乎都是块级元素)。垂直方向也类似。关于元素格式化的详细信息移步至此

  但是对于绝对定位元素则不相同。它的水平格式化等式为:

left + margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right + right = 包含块的 clientWidth

  类似的,垂直格式化等式为:

top + margin-top + border-top-width + padding-top + height + padding-bottom + border-bottom-width + margin-bottom + bottom = 包含块的 clientHeight

auto

  auto 值是用来弥补实际值与所需总和的差距。

  水平方向上,可以为 auto 的属性有 left、margin-left、width、margin-right、right。类似地,垂直方向上,可以为 auto 的属性有 top、margin-top、height、margin-bottom、bottom

【0 个 auto】

  当水平方向上 9 个值的和不等于包含块的 clientWidth 时,属于过度受限的情况,right 值会被重置为 auto;类似地,当垂直方向上 9 个值的和不等于包含块的 clientHeight 时,属于过度受限的情况,bottom 值会被重置为 auto

【1 个 auto】

  根据水平和垂直格式化等式,auto 为计算值

【2 个 auto】

  当 margin-left 和 margin-right 同时为 auto 时,margin-left 和 margin-right 都为等式计算值且相等

  [注意] 在 margin-left 和 margin-right 同时为 auto 的情况下,只有当 left 和 right 值相等时,元素才能水平居中显示;否则,虽然 margin-left 和 margin-right 依然相等,但由于 left 和 right 并不相等,元素也不能水平居中

  当 margin-left 或 margin-right 不同时为 auto 时,值为 auto 的 margin-left 或 margin-right 被置为 0

  当 width 与 left 或 right 同时为 auto 时,width 被置为宽度最小值 (内容宽度)

  当 left 和 right 同时为 auto 时,则 left 为置为 0

  类似地,

  当 margin-top 和 margin-bottom 同时为 auto 时,margin-top 和 margin-bottom 都为等式计算值且相等

  [注意] 在 margin-top 和 margin-bottom 同时为 auto 的情况下,只有当 top 和 bottom 值相等时,元素才能垂直居中显示;否则,虽然 margin-top 和 margin-bottom 依然相等,但由于 top 和 bottom 并不相等,元素也不能垂直居中

  当 margin-top 或 margin-bottom 不同时为 auto 时,值为 auto 的 margin-top 或 margin-bottom 被置为 0

  当 height 与 top 或 bottom 同时为 auto 时,height 被置为高度最小值 (行高)

  当 top 和 bottom 同时为 auto 时,则 top 为置为 0

【3 个 auto】

  当 margin-left 和 margin-right 同时为 auto 时,margin-left 和 margin-right 都被置为 0

  当 margin-left 和 margin-right 不同时为 auto 时,值为 auto 的 margin-left 或 margin-right 被置为 0

  除了 width、margin-left 和 margin-right 同时为 auto 时,margin-left 和 margin-right 都置为 0,width 为等式计算值;其他情况下,width 都被置为宽度最小值 (内容宽度)

  当 left 和 right 同时为 auto 时,则 left 为置为 0

  类似地,

  当 margin-top 和 margin-bottom 同时为 auto 时,margin-top 和 margin-bottom 都被置为 0

  当 margin-top 和 margin-bottom 不同时为 auto 时,值为 auto 的 margin-top 或 margin-bottom 被置为 0

  除了 height、margin-top 和 margin-bottom 同时为 auto 时,margin-top 和 margin-bottom 都置为 0,height 为等式计算值;其他情况下,height 都被置为高度最小值 (行高)

  当 top 和 bottom 同时为 auto 时,则 top 为置为 0

【4 个 auto】

  当 width 不为 auto 时,margin-left 和 margin-right 被置为 0,left 被置为 0,right 为计算值

  当 left 不为 auto 时,margin-left 和 margin-right 被置为 0,width 被置为宽度最小值 (内容宽度),right 为计算值

  当 right 不为 auto 时,margin-left 和 margin-right 被置为 0,width 被置为宽度最小值 (内容宽度),left 为计算值

  当 margin-left 不为 auto 时,left 和 margin-right 被置为 0,width 被置为宽度最小值 (内容宽度),right 为计算值

  当 margin-right 不为 auto 时,left 和 margin-left 被置为 0,width 被置为宽度最小值 (内容宽度),right 为计算值

  类似地,

  当 height 不为 auto 时,margin-top 和 margin-bottom 被置为 0,top 被置为 0,bottom 为计算值

  当 top 不为 auto 时,margin-top 和 margin-bottom 被置为 0,height 被置为高度最小值 (行高),bottom 为计算值

  当 bottom 不为 auto 时,margin-top 和 margin-bottom 被置为 0,height 被置为高度最小值 (行高),top 为计算值

  当 margin-top 不为 auto 时,top 和 margin-bottom 被置为 0,height 被置为高度最小值 (行高),bottom 为计算值

  当 margin-bottom 不为 auto 时,top 和 margin-top 被置为 0,height 被置为高度最小值 (行高),bottom 为计算值

【5 个 auto】

  left、margin-left 和 margin-right 被置为 0,width 被置为宽度最小值 (内容宽度),right 为计算值

  类似地,top、margin-top 和 margin-bottom 被置为 0,height 被置为高度最小值 (行高),bottom 为计算值

总结

  auto 值的赋值顺序为:margin 先置 0 或其他值,然后宽高置为最小值,然后 left/top 置为 0,最后 right/bottom 为等式计算值

  [注意 1]IE7- 浏览器不支持绝对定位元素通过将上下外边距设置为 auto 来实现垂直居中的行为

  [注意 2]IE6- 浏览器不支持绝对定位元素不设置宽度,而通过设置 top/left/right/bottom 来撑开宽高的行为

//DEMO 中,定位元素的 padding、border 都为 0。而父级元素也就是包含块的 width 和 height 都设为 200px,边框为 2px