CSS绝对定位absolute详解

返回:一般常见样式处理及开发技巧 | 返回:css属性position处

::: tip 包裹性 和 高度欺骗

一旦给元素加上absolute或float就相当于给元素加上了display:block;

什么意思呢?
比如内联元素span默认宽度是自适应的,你给其加上width是不起作用的。要想width定宽,你需要将span设成display:block。
但如果你给span加上absolute或float,那span的display属性自动就变成block,就可以指定width了。
因此如果看到CSS里absolute/float和display:block同时出现,那display:block就是多余的CSS代码。 :::

如何确定定位点

返回顶部

一旦absolute分层后,第一个出现的问题就是让浏览器在何处显示该元素。普通文档流里的元素,浏览器可以根据其父子兄弟元素的大小和位置,计算出该元素的位置。但分层后怎么办?

  • 第一种情况:用户只给元素指定了absolute,未指定left/top/right/bottom。此时absolute元素的左上角定位点位置就是该元素正常文档流里的位置。如上面图例中,图片熊猫是父元素的第一个孩子,因此左上角定位点就是父元素的content的左上角。

2020-10-26_151349.jpg

  • 第二种情况:用户给absolute元素指定了left/right,top/bottom
  • 只指定left时,元素的左上角定位点的left值会变成用户指定值。但top值仍旧是该元素在正常文档流中的top值
  • 只指定right时,元素的右上角定位点的right值会变成用户指定值。但top值仍旧是该元素在正常文档流中的top值

::: tip 通过对left/top/right/bottom的组合设置,由于没有position:static以外的父元素,此时absolute元素可以去任意它想去的地方,天空才是它的极限。 :::

和relative相爱相杀

返回顶部

::: tip 如果absolute元素没有position:static以外的父元素,那将相对body定位,天空才是它的极限。而一旦父元素被设为relative,那absolute子元素将相对于其父元素定位,就好像一只脚上被绑了绳子的鸟。 :::

.withAbsoluteDiv {
  border: 3px dashed #e1622f;
  //position: absolute;
  position: relative;
  display: inline-block; // 这个很重要,否则将很难调整徽标的位置
}

.badgeDigit {
  border: 1px solid #b7d28d;
  background-color: #f00;
  color: #fff;
  border-radius: 50%;
  text-align: center;
  position: absolute;
  width: 30px;
  height: 30px;
  right: -15px;
  top: -15px;
  font-size: 18px;
}
<div className={ styles.withAbsoluteDiv }>
    <img alt="rmb11" src={ rmb12 } height={63}/>
    <span className={styles.badgeDigit}>首</span>
</div>

2020-10-26_153146.jpg

如果没有display: inline-block;,则效果图如下:

2020-10-26_154112.jpg

这样做效果是OK的,兼容性也OK。但CSS的世界里要实现一个效果可以有很多种方式,具体选用哪个方案是见仁见智的。我比较看重的标准:一个是简洁,另一个是尽量让每个属性干其本职工作

用这两个标准看待上述实现方法,应该是有改进的空间的。首先外层div多了relative未能简洁到极致。其次relative的本职工作是让元素在相对其正常文档流位置进行偏移,但父层div并不需要任何位置偏移,之所以设成relative唯一的目的是限制absolute子元素的定位点。
用父relative + 子absolute来实现定位,万一将来页面布局要调整,父元素的尺寸需要变换呢?则会出现错位现象

::: tip 未指定left/top/right/bottom的absolute元素,其在所处层级中的定位点就是正常文档流中该元素的定位点。 :::

.withAbsoluteDiv {
  border: 3px dashed #e1622f;
  display: inline-block;
}

.badgeDigit2 {
  border: 1px solid #b7d28d;
  background-color: #f00;
  color: #fff;
  border-radius: 50%;
  text-align: center;
  position: absolute;
  width: 30px;
  height: 30px;
  font-size: 18px;
  margin: -15px -15px 0 0;
}

这么说来relative和absolute是否应该彻底断绝关系呢?不是这样的,这段的标题是“和relative相爱相杀”,刚才说的想杀部分,现在说下什么相爱部分。

全屏覆盖、遮罩层

absolute常见的一个案例是透明层覆盖元素

::: tip 用absolute的left: 0;right: 0;top: 0;bottom: 0;来实现全屏拉伸,对于absolute元素来说,如果同时设置left和right会水平拉伸,同时设置top和bottom会垂直拉伸。 :::

.withAbsoluteDiv {
  border: 3px dashed #e1622f;
  display: inline-block;
}
<div className={ styles.withAbsoluteDiv }>
    <img alt="rmb11" src={ rmb12 } height={63}/>
    {/* <span className={styles.badgeDigit}>首</span> */}
    <span className={styles.badgeDigit2}>二</span>
</div>
<span className={styles.cover} />

2020-10-26_162706.jpg

::: danger 那为何不设width/height为100%呢?
前面说了,不设top/right/top/bottom的话absolute会从正常文档流应处的位置开始定位,因此做不到全屏。
除非你设置width/height为100%后,同时再设left: 0; top: 0;。这样就显得很啰嗦。 :::

部分遮罩

只希望给图片部分设置滤镜呢?用js计算图片的大小尺寸和定位点后,设置absolute滤镜的尺寸和定位点?太麻烦了。用relative吧

.withAbsoluteDiv {
  border: 3px dashed #e1622f;
  position: relative;
  display: inline-block;
}
<div className={ styles.withAbsoluteDiv }>
    <span className={styles.cover} />
    <img alt="rmb11" src={ rmb12 } height={63}/>
    {/* <span className={styles.badgeDigit}>首</span> */}
    <span className={styles.badgeDigit2}>二</span>
</div>

2020-10-26_162501.jpg

和relative相爱相杀-结论

  • 1.相对定位时,不必拘泥于relative+absolute,试试去掉relative,充分利用absolute自身定位的特性,将relative和absolute解耦。耦合度越低维护起来越容易,前端仔腾出时间陪女朋友吃饭才是正道。
  • 2.拉伸平铺时,用relative可以有效限制子absolute元素的拉伸平铺范围(注意是拉伸,不是缩小。要缩小请再加上width/height:100%;)

和z-index的关系

返回顶部

::: tip z-index被太多的滥用了。几乎成了个定势思维:只要设了absolute就需要同步设置z-index。其实不是这样的。 :::

  • 以下情况根本不需要设z-index:
  • 让absolute元素覆盖正常文档流内元素(不用设z-index,自然覆盖)
  • 让后一个absolute元素覆盖前一个absolute元素(不用设z-index,只要在HTML端正确设置元素顺序即可)

什么时候需要设置z-index

  • 当absolute元素覆盖另一个absolute元素,且HTML端不方便调整DOM的先后顺序时,需要设置z-index: 1。非常少见的情况下多个absolute交错覆盖
  • 或者需要显示最高层次的模态对话框时,可以设置z-index > 1。

::: tip 如果你的页面不比京东更复杂,那z-index通常设成1,2,3足够了 :::

减少重绘和回流的开销

返回顶部

::: tip 例如将元素隐藏,你或许会用display:none。 :::

其实我更推荐的是absolute控制隐藏和显示。
方法当然相当简单,
absolute+ top:-9999em,或absolute + visibility:hidden

::: tip 考虑到重绘和回流的开销,可以将动画效果放到absolute元素中,避免浏览器将render tree回流。 :::