深挖CSS:你真的知道position和absolute吗?

904 阅读6分钟

头条面试官一直在深挖absolute的作用。回答的过程中,我提到了有bfc的作用,然后又继续深挖bfc。

回答几个属性值是static、absolute、relative、fixed、sticky并解答一些基本特性。

absolute是绝对定位,能够脱离文档流,通过top,right,bottom和left,相对第一个position不为static的祖先元素来定位。

这是基本的回答,显然不能符合头条面试官的要求。

以下是深入的回答,准备发车了!!!

1、包裹性与包含块

此特性与float一样,即声明为absolute时,如果不设置宽度,其宽度由里面的内容撑起来,表现为像“包裹”一样。想一想平时在开发中,是不是定义了absolute之后,还要再设置它的width

在CSS世界里,元素的大小和定位计算一直都要受包含块的影响,如果没有包含块,那么元素的信息就会像txt文本一样,全都显示在一行,这显然是不符合我们的阅读标准的,通常情况下我们希望文本信息能在某些符合常理的情况下自动换行,既然能换行,就必须要有包含块的概念,有经验的人一般都知道,普通元素的包含块一般是他的父容器,也就是你设置某个元素的宽度为100%,那么指的是相对于父容器的宽度进行计算后得到的宽度,而绝对定位元素的包含块是相对于第一个position不为static的祖先元素进行计算的,由于包含块在CSS世界的重要性,CSS规范中有明确的计算规则如下:

  1. 根元素(通常情况下就是html)被称为初始包含块,其尺寸等同于浏览器可视窗口的大小。

  2. 对于position:relative/static(默认)的元素,其包含块由其最近的块容器祖先盒的content-box边界形成。

  3. 对于position:fixed的元素,其包含块指的是初始包含块。

  4. 对于position:absolute的元素,其包含块由最近的position不为static的祖先元素的padding-box建立(如果祖先元素为块元素)。如果没有符合条件的包含块,则包含块是初始包含块。

扩展:height:100%;和height:inherit;的区别?

对于普通元素,两者没什么区别,但absolute元素就不一样。height:100%;是第一个具有定位属性值的祖先元素的高度,而height:inherit;则是单纯的父元素的高度继承。

.wrapper {
    position: relative;
    height: 200px;
    border: 1px solid #f00;
  }
 .father {
    height: 100px;
    border: 1px solid #0f0;
  }
 .child {
    /*关键在这里*/
    /* height: 100%; */
    height: inherit;
    border: 1px solid #000;
    position: absolute;
    width: 100%;
  }
<div class="wrapper">
  <div class="father">
    <div class="child"></div>
  </div>
</div>

2、具有相对特性的无依赖absolute定位

在实际业务开发中,遇到要调整icon的位置时,可以考虑使用这个特性,超级好用。

当绝对定位没有任何left/top/right/bottom属性设置时,并且祖先元素全部都是非定位元素,其位置在哪里?

第一反应是不是认为是在浏览器窗口的左上方。实际上,还是在当前位置,只是它不占据布局的空间。然后它可以通过margin属性进行定位,来调整icon所处的位置。

3、absolute的流体特性

想想怎么垂直居中布局?

当absolute遇到left/top/right/bottom属性的时候,absolute元素才是真正变成绝对定位元素。

说到流体特性,第一反应是 <div> 之类的普通块级元素。块级元素的水平具有流体特性,于是在子块级元素设置margin:0 auto; 时,能够相对父块级元素水平居中布局。

在absolute中,如果同时拥有left:0;right:0; 这两个属性值,则水平方向具有流体特性;同样的,如果同时拥有top:0;bottom:0; 这两个属性值,则垂直方向具有流体特性。因此,设置margin:auto;,则能让绝对定位元素保持垂直水平居中布局。

.absCenter {
    position: absolute;
    left: 0; right: 0; top: 0; bottom: 0;
    margin: auto;
    width: 100px;
    height: 100px;
  }

在垂直居中布局的方法中,首推上面的方法。

4、块状化

绝对定位能使元素块状化,使得display变为block。

var span = document.createElement('span');
document.body.appendChild(span);
console.log('1.' + window.getComputedStyle(span).display);
span.style.position = 'absolute';
console.log('2.' + window.getComputedStyle(span).display);
输出:
1.inline
2.block

absolute还有很多特性,感兴趣的可以看看《CSS世界》

【扩展】什么是BFC?

BFC(Block Formatting Context)直译为“块级格式化上下文 ”。

BFC是一个独立的布局环境,可以理解为一个看不见的盒子,盒子内部的物品摆放不受外界环境影响,相当于一个“结界”,内外互不影响(我们往往用此特性消除浮动元素对其非浮动的兄弟元素和子元素带来的影响),在同一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。

总结BFC的特征:

  1. BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。 BFC内部的Box会在垂直方向,一个接一个地放置。
  2. Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的垂直margin会发生重叠
  3. 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  4. 计算BFC的高度时,浮动元素也参与计算(可用于解决浮动造成的高度塌陷问题) BFC的区域不会与float box重叠(解决浮动元素文字环绕问题)

如何触发BFC?

根据定义,满足下列条件中至少一项,即可触发 BFC:

  1. <html>根元素
  2. (浮动)float 的值不为none
  3. (定位)position 的值不为static或者relative
  4. (修剪)overflow的值不为visible
  5. (展示)display的值为 table-cell, table-caption, inline-block, flex, 或者 inline-flex中的其中一个

平常开发中,用的最多的是,通过overflow:hidden;来触发BFC。

产生折叠的必备条件:margin必须是邻接的!

浮动和绝对定位不与任何元素产生 margin 折叠。 原因:浮动元素和绝对定位元素不与其他盒子产生外边距折叠是因为元素会脱离当前的文档流,违反了上面所述的两个margin是邻接的条件同时,又因为浮动和绝对定位会使元素为它的内容创建新的BFC,因此该元素和子元素所处的BFC是不相同的,因此也不会产生margin的折叠。