# 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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div className={ styles.withAbsoluteDiv }>
    <img alt="rmb11" src={ rmb12 } height={63}/>
    <span className={styles.badgeDigit}></span>
</div>
1
2
3
4

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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

这么说来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;
}
1
2
3
4
<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} />
1
2
3
4
5
6

2020-10-26_162706.jpg

WARNING

那为何不设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;
}
1
2
3
4
5
<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>
1
2
3
4
5
6

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回流。