CSS原理解析之模型篇

5,181 阅读7分钟

写在前面:

尝试回答几个问题:
  1. 什么是盒模型,控制盒模型的属性有哪些?
  2. Margin、Padding、Border、Width、Height这些属性改变/影响盒模型,但每个属性都会在所有元素上生效么?
  3. 如果存在区别,那么和元素类型或者元素定位有关系么?
  4. 浮动元素是什么?位置如何确定?如果去掉浮动?
  5. 层叠关系如何判断优先级?越大就越靠近用户么?
盒模型是我们每天都在接触的,但盒子模型到底如何计算排列的,总是一知半解。本文尝试从W3C规范和实例入手,解决上述问题。

目录

包含块(containing block)
盒模型(Box model)
定位模式(Positioning schemes)
层叠关系(Layered presentation)

包含块

概念
每个盒子会变成他后代盒子的包含块,后代盒子的大小和位置会根据他包含块的矩形边框进行计算。但是不会受到包含块的限制,可能会溢出。
确定包含块的方法
  1. 对于根元素、position=fixed的元素,包含块都是视窗
  2. 如果元素是relative或者static,则是他最近的块形父元素的内容区(content)——注:规定了父元素必须是block container
  3. 如果元素是absolute,包含块是最近的非static的父元素的Padding区——注:父元素的类型未规定
举例
包含块最直观的判断是一个元素对大小设置百分比时,相对的元素是哪一个,这个元素就是他的包含块
1. 最基本的例子
2. 当em变成absolute定位

盒模型

Margin
  1. 宽度。分为四个方向,都支持百分比和具体的像素。并且margin的百分比是根据元素的包含块(containing-block)的width来计算。并不是margin-top/ bottom对应height。示例代码
  2. 内联元素(display: inline)的margin-top和margin-bottom失效。浏览器不允许设置。
  3. 合并。
    • 水平的margin不会合并(inline-block和inline都支持) 示例代码
    • 都属于常规流内(in flow)块级盒,处于同一个上下文的兄弟元素 解决方法:将其中一个块盒变成BFC,阻止margin的合并 示例代码
    • 块级父元素和其子元素,在没有padding,border,height,空隙将之隔开时,子元素的margin会渗透到父元素上。简单讲,父元素和子元素之间没有其他元素。示例代码
  4.  允许设置负值。
    • 对于position=static元素,负值相当于将元素向负值方向移动覆盖,但是只会覆盖颜色,不会覆盖文字。示例代码
    • 对于position=relative元素, 负值还是会把下面的元素粘着一起移动,但会完全覆盖前一个元素。示例代码
    • 对于position=absolute元素,因为元素脱离了文档流,所以负值只会自己发生偏移,对前后元素没有任何影响。示例代码
    • 对于float元素,可以通过负值进行覆盖,最常见的应用是三栏应用。示例代码
Padding
  1. 宽度。同Margin。
  2. 内联元素(display: inline)的padding生效,但是top和bottom并不会推挤,只会覆盖其他元素,覆盖情况遵循z-index原则。示例代码
  3. 合并。Padding不存在合并情况示例代码
  4. 不允许负值。
Border
  1. 宽度。只有px,不支持百分比。
  2. 合并。inline元素左右不合并,上下会合并。inline-block&block元素四个方向都不会合并示例代码
Width
  1. 内联元素不能设置width和height。
  2. 非内联元素百分比设置(见上文包含块)
    • 根据包含块的content box宽度计算
    • 如果当前元素是绝对定位,那么相对父元素的padding box的宽度定位
Height
计算方式同width

定位模式

常规流
流内元素有几大模型。CSS2.1中定义了IFC(Inline Formatting Contexts)与 BFC(Block Formatting Contexts)。CSS3中增加了GFC(GridLayout Formatting Contexts)和FFC(Flex Formatting Context)。后两个后续文章会详细讲解,这里暂且不提。
BFC(Block formatting contexts)块格式化上下文
  1. 什么情况产生BFC(四选一)
    • 浮动
    • 绝对定位
    • 非块盒的块容器(inline-block)
    • overflow不为visible的块盒
   2. 特性
    • 从包含块顶部竖直方向排列
    • BFC内部兄弟盒子之间的margin会合并——可以通过把兄弟之一变成BFC解决合并
    • BFC可以阻止margin合并
IFC(Inline formatting contexts)内联格式化上下文
  1. 如何产生:只有在一个块级元素中仅仅包含内联级别元素时才会生成
  2. 特性
    • 从包含块顶部水平方向排列
    • 排列情况和浮动与否会改变行盒的高度
    • 当一个行盒被分割,margin,border,padding都不会再有视觉效果了
浮动
  1. 概念:float CSS属性指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它。该元素从网页的正常流动中移除,尽管仍然保持部分的流动性
  2. 位置:
    • 当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素
    • 浮动元素会根据上一个元素的类型判断位置,如果上一个是浮动的,则跟随他,放不下就挤到下一行
    • 如果上一个是标准流的元素,则浮动元素的相对垂直高度不变,顶部和上一个元素的底部对齐。
   3. 清除浮动
    • 引入空隙,父元素使用::after伪元素
    • 浮动元素限制成BFC,使用overflow:hidden
    • clear属性
   4. 代码:示例代码
绝对定位
position=absolute设置元素绝对定位,会导致元素变成绝对定位,脱离文档流,并且元素此时是BFC布局,Margin不会进行合并。使用top/bottom/left/right(下面简写成TBLR)控制位置的变动,具体像素和百分比都参照包含块进行偏移。
比较其他position属性值
  1. position=static 常规流布局,无法通过TBLR控制位置
  2. position=relative 盒子相对于其常规流位置进行偏移,兄弟元素相对其偏移前的位置定位。使用TBLR控制时,如果是固定像素,那盒子相对于自身边界偏移,如果是百分比,则参照包含块偏移。
  3. position=fixed 包含块是视窗,使用TBLR控制都是相对包含块偏移
  4. 对于百分比:left/right 相对于包含块的width,top/bottom相对于包含块的height

层叠关系

在一个层叠上下文中一共可以有7种层叠等级,列举如下:示例代码
  1. 背景和边框 —— 形成层叠上下文的元素的背景和边框。 层叠上下文中的最低等级。
  2. 负z-index值 —— 层叠上下文内有着负z-index值的子元素。
  3. 块级盒 —— 文档流中非行内非定位子元素。
  4. 浮动盒 —— 非定位浮动元素。
  5. 行内盒 —— 文档流中行内级别非定位子元素。
  6. z-index: 0 —— 定位元素。 这些元素形成了新的层叠上下文。
  7. 正z-index值 —— 定位元素。 层叠上下文中的最高等级。
当对某一个元素的z-index赋值了除了auto以外的值,就创建了一个新的层叠上下文,独立于其他的层叠上下文。
比较顺序变成,先比较各个层叠上下文的z-index。然后在层叠上下文中比较子元素的优先级。

总结

  1. 本文解释包含块,以及基于包含块确定的盒模型,对盒模型的四个边界的计算方式做了总结。
  2. 对元素的定位方式和不同定位方式引起的元素之间位置变化做了总结。
  3. 后续会继续以总结形式梳理CSS中常见但迷惑的地方。
  4. 如有错误,请指出,大家一起共同进步~