>

深入理解css偏移,深入理解视觉格式化模型

- 编辑:至尊游戏网站 -

深入理解css偏移,深入理解视觉格式化模型

深入理解视觉格式化模型

2016/08/31 · CSS · 1 评论 · CSS, 绝对定位

原文出处: 腾讯 ISUX - 他大舅   

“理论不懂就实践,实践不会就学理论”,非常赞同bluedavy的这句话。实践过程中经常会遇到某个属性的使用,浏览器渲染效果与预期效果不符,虽然通过死记硬背能避免或巧妙应用这种效果,但总感心虚发慌、毫无自信,因为不知晓背后的原理。这时就不要再用“就是这样的”的借口来搪塞自己,我们需要重新认识它。

深入理解CSS定位中的偏移,深入理解css偏移

×

实践与现象

绝对定位是一种常用的定位方式,也经常会看到一些使用技巧,轻松搞定一些不太容易实现的效果。现介绍两个绝对定位的使用技巧:

1. 绝对定位元素,水平方向(top和bottom)或和垂直方向(left和right)的定位值不设置时,其位置受其前面的兄弟元素影响,如同其在常规流中的位置。如下例所示:

  • 元素A,C绝对定位,不设置top,bottom值;
  • 元素B处于常规流中;

结果是:元素C的位置受元素B的影响,跟随在元素B的下方。

See the Pen absolute-position by wenjul (@wenjul) on CodePen.

这种看似毫无用处的技巧,却能帮助我们解决一些项目实际问题。我们总希望我们的布局是自适应的,即不依赖与所处环境,当环境改变时,仍能完美工作。下面这个实例要求蓝色购买按钮水平居中,其后跟随一个链接。为了达到自适应布局,我们不能假设父级容器宽度固定,也不能假设蓝色按钮的文案固定,所以链接元素的位置也是根据上下文环境改变的。这种情况下,我们就可以对链接设置绝对定位,并且不用设置left 和right 值,两者的间距通过margin值实现,即可轻松达到预期效果。(当然,通过嵌套的方式也可实现,但不是最优解)

See the Pen center-el-followed-by-link by wenjul (@wenjul) on CodePen.

另一个案例是用以实现下拉菜单,下拉菜单通常由触发按钮和下拉列表组成,下拉列表的位置位于触发按钮的下方。同样,由于触发按钮的高度是可能变化的,那么下拉列表与触发按钮顶端的绝对距离是不固定的,使用单位px是无法达到自适应的,通常的技巧是设置top:100%,其实利用我们上面提到的技巧,对top和bottom不设置值也是可以实现的。

See the Pen dropdown menu by wenjul (@wenjul) on CodePen.

2. 绝对定位结合margin实现垂直居中

很多设计都可以抽象为“一个元素相对于父级(或包含块)在垂直方向或水平方向上居中对齐”的模式,根据实际情况又可分为该元素的尺寸未知和已知两种情况。这是个经久不衰的话题,实现方式也多种多样,这里我们讨论的是“尺寸已知元素在垂直方向上的居中对齐”问题。你可能看到过下面这种实现方式,绝对定位元素的4个值均为0,margin在垂直方向上也设置为了auto(支持IE8+)。一般为了水平居中会在水平方向上设置auto,为什么这种情况下,在垂直方向上设置auto,会导致垂直居中的效果呢?

See the Pen center-middle by wenjul (@wenjul) on CodePen.

目录

[1]定位 [2]包含块 [3]偏移属性[4]绝对定位[5]格式化 [6]auto

规范与原理

为了解决这个疑虑,我重新学习了CSS 2.1规范中的 9 Visual formatting model 和 10 Visual formatting model details,现将相关章节译录于此。

这两章讲解了视觉格式化模型:用户代理在视觉媒体上如何处理文档树。在视觉格式化模型中,文档树中的每个元素根据框模型(box modal)生成0或多个框。这些框的布局由以下因素决定:

  • 框尺寸和类型
  • 定位方案(常规流、浮动和绝对定位)
  • 文档树中元素之间的关系
  • 外部信息(比如viewport尺寸、图像的固有尺寸等)

9.1.2 Containing blocks(包含块)

CSS 2.1中,许多框的位置和尺寸的计算是相对于一个矩形框的边缘,这个矩形框称为包含块。通常情况下,生成框是后代框的包含块(generated boxes act as containing blocks for descendant boxes;),称之为一个框为其后代创建了包含块。短语“一个框的包含块”指的是“这个框存在其中的包含块”,而非它生成的框。 每个框会相对于其包含块赋予位置,但它并不囿于包含块,可能会溢出(overflow)。包含块的尺寸计算细节在第10章有详细介绍。

前面的话

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

 

9.2 Controlling box generation(控制框生成)

本节描述了CSS 2.1中可生成的框类型。一个框的类型部分地影响其在视觉格式化模型中的行为。

9.2.1 Block-level elements and block boxes

处在块格式化环境(BFC,block formatting context)中的框称之为块级框(block-level box)。每个块级元素生成一个包含后代框和生成的内容的主体块级框,同时这个框与定位方案密切相关。有些块级元素除了生成主体框外,还会生成一个附加框,如’list-item’元素。附加框相对于主体框定位。 表框(table boxes)和替换元素(replaced elements)外,块级框同时也是块容器框(block container box)。块容器框要么仅包含块级框,要么建立一个行内格式化环境(IFC,inline formatting context),即仅包含行内级框。并非所有的块容器框都是块级框:非替换行内块(inline blocks)和非替换表格单元格都是块容器,但不是块级框。既是块级框也是块容器的框称为块框(block box)。 “块级框”、“块容器框”和“块框”这三个术语有时被简称为块(block)

9.2.3 Run-in boxes(插入型框)

CSS Level 3的CSS basic box model中定义。 run-in框的行为如下:

  1. 如果run-in框包含一个块框,那么run-in框变为块框。
  2. 如果run-in框的后继兄弟元素为块框(非浮动,非绝对定位),那么run-in框变为该块框的第一个行内框。run-in不能插入本身为run-in的块中,也不能插入块中已有run-in的块中。
  3. 否则,run-in框变为块框。

浏览器支持:IE8+(chrome不支持,难道是太鸡肋?)IE下查看效果

图片 1

9.3.2 Box offsets: ‘top’, ‘right’, ‘bottom’, ‘left’

  • (绝对、固定)定位元素会生成一个定位框(positioned box),根据top,right,bottom,left布局。
  • 初始值为auto,非0。(文章开头的问题中未设置四值,等同设置为auto
  • 对于绝对定位元素,四值指定的是元素margin边与包含块的边之间的偏移量。对于相对定位元素,四值指定的是相对于自身框边的偏移量。

position定位

  值: static | relative | absolute | fixed | inherit

  初始值: static

  应用于: 所有元素

  继承性: 无

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

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

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

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

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

 

9.6 Absolute positioning

  • 从常规流中完全抽离,对其后继兄弟元素无影响。
  • 固定定位是绝对定位的特例,它的包含块是viewport。

包含块

【1】根元素

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

【2】非根元素

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

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

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

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

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

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

 

9.7 Relationships between ‘display’, ‘position’, and ‘float’

这三个属性影响了框的生成和布局,相互影响如下:

  1. 如果’display’值为’none’,同时不设置’position’和’float’,那么该元素不生成框。
  2. 否则,如果’positon’值为’absolute’或’fixed’,即框为绝对定位,’float’的计算值为’none’,并且’display’根据下表设置。那么该框的位置由’top’,’right’,’bottom’,’left’和框的包含块决定。
  3. 否则,如果’float’的值不为’none’,那么该框会浮动,’display’根据下表设置。
  4. 否则,如果该元素为根元素,’display’根据下表设置。
  5. 否则,剩余的’display’属性值与指定值相同。
指定值 计算值
inline-table table
inline, table-row-group, table-column, table-column-group, table-header-group, table-footer-group, table-row, table-cell, table-caption, inline-block block
others same as specified

偏移属性

  三种定位机制使用了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区域

 

10.6 Calculating heights and margins(高度和margin值计算)

10.6.4 Absolutely positioned, non-replaced elements(绝对定位的非替换元素)

静态位置(static position),粗略地讲是指一个元素在常规流中的位置。精确地讲,一个元素的静态top值,是指包含块顶部边沿与该元素的假想框的顶部margin边沿之间的距离。假想框是指如果该元素的’position’值为’static’,以及’float’值为’non’且’clear’值为’none’时,该元素的第一个框。 对于绝对定位的元素,垂直尺寸的使用值必须满足下面约束:

‘top’ + ‘margin-top’ + ‘border-top-width’ + ‘padding-top’ + ‘height’ + ‘padding-bottom’ + ‘border-bottom-width’ + ‘margin-bottom’ + ‘bottom’ = height of containing block

如果’top’,’bottom’,’height’值均为auto,那么’top’值为元素的静态位置。(这也就回答了文章开头的问题) 如果三个值均不为auto,那么:

  • 如果’margin-top’和’margin-bottom’值均为’auto’,那么假定margin-top和margin-bottom两值相等,然后再解上面方程式。(上述的第二个垂直居中案例就是利用了这一点 
  • 如果’margin-top’和’margin-bottom’值中其一为’auto’,解上面方程式获取该margin值。
  • 如果数值超过限制,忽略’bottom’值,解方程式获取该值。

否则,从以下六种规则中挑选适用情况:

  1.  ‘top’和’height’为’auto’,’bottom’不为’auto’,那么’height’基于其内容根据10.6.7规则计算,’margin-top’值设为’auto’,’margin-bottom’值设为0,解方程式得’top’值。
  2.  ‘top’和’bottom’为’auto’,’height’不为’auto’,那么设置’top’值为其静态位置,’margin-top’值设为’auto’,’margin-bottom’值设为0,解方程式得’bottom’值。
  3.  ‘bottom’和’height’为’auto’,’top’不为’auto’,那么’height’基于其内容根据10.6.7规则计算,’margin-top’值设为’auto’,’margin-bottom’值设为0,解方程式得’bottom’值。
  4.  ‘top’值为’auto’,’bottom’和’height’不为’auto’,那么’margin-top’值设为’auto’,’margin-bottom’值设为0,解方程式得’top’值。
  5.  ‘height’值为’auto’,’bottom’和’top’不为’auto’,那么’margin-top’值设为’auto’,’margin-bottom’值设为0,解方程式得’height’值。
  6.  ‘bottom’值为’auto’,’height’和’top’不为’auto’,那么’margin-top’值设为’auto’,’margin-bottom’值设为0,解方程式得’bottom’值。

    1 赞 3 收藏 1 评论

图片 2

绝对定位

  元素绝对定位时,会从文档流中完全删除。然后相对于其包含块定位,其边界根据偏移属性(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

图片 3

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

目录 [1]定位 [2]包含块 [3]偏移属性[4]绝对定位[5]格式化 [6]auto 前面的话 CSS有三种基本的定位机...

本文由技术教程发布,转载请注明来源:深入理解css偏移,深入理解视觉格式化模型