你可能不知道的绝对定位

1,666 阅读7分钟

欢迎关注我的公众号:前端侦探

分享一个关于绝对定位的实战开发经验。

在普遍的认知下,绝对定位好像都是伴随着偏移属性(left/right/top/bottom)一起出现的,相信大家都写过这样的CSS,如下

el{
  position: absolute;
  left: 0;
  top: 0;
}

其实,有些情况下是可以不需要偏移量的,不仅实现上更加简洁,适应性也更强,甚至还能实现加上偏移量反而实现不了的布局,一起看看吧,相信会有不一样的体会

一、绝对定位的特性

谈到绝对定位布局,大家可能会马上就会想到这些特性:

  • 不占用空间
  • 脱离文档流

第一条没什么问题,确实不会占用空间。现在来看第二条,真的完全脱离文档流了吗?假设有这样一个布局

<p>
  欢迎关注前端侦探
</p>

然后生成一个伪元素,设置成绝对定位

p::after{
  content: 'A';
  position: absolute;
  color: red;
}

在不设置任何偏移的情况下,可以看到,绝对定位元素始终跟随在文本后面,也就是说,现在仍然处于文档流中,如下

image.png

如果仅设置一个方向,比如left

p{
  position: relative;
}
p::after{
  content: 'A';
  position: absolute;
  color: red;
  left: 0;
}

那么,在水平方向上,绝对定位元素始终位于最左边,而垂直方向上,仍然保持着跟随文档的特性,只是单方向的

image.png

如果两个方向上都设置了,这也是我们最常见的写法

p::after{
  content: 'A';
  position: absolute;
  color: red;
  left: 0;
  top0
}

那么,这个元素位置就完全固定了,真正的脱离了文档流

image.png

综上所述,绝对定位元素,只有在设置了偏移时才会脱离文档流,如果只设置了一个方向上的,那么在另外一个方向上仍然保留着文档流特性,或者这么说,绝对定位元素仍然保持在原来的位置,并且不占空间,除非设置了偏移才会真正固定定位

了解了这些,下面来看几个实际案例

二、左上角的标签

大家可能经常会碰到这样的“角标”效果

image.png

现在简单实现一下,假设HTML是这样的

<div class="item">
  <img class="cover" src="xxx">
</div>

角标可以通过伪元素生成

.item::before{
  content: '推荐';
  position: absolute;
  font-size: 12px;
  line-height: 16px;
  padding: 2px 4px;
  background: #FDB324;
  color: #fff;
}

注意,这里用到的是::before,而不是::after,原因在于::before在元素内容之前,本身就位于左上角,如果是::after,默认位置就在img的下方,在设置position: absolute的情况下,由于不占空间,所以也不影响其他元素,效果如下

image.png

因此,像这种场景下,设置偏移量和父级定位可以说都是多余的

/*以下是多余的*/
.item{
  position: relative;
}
.item::before{
  left: 0;
  top: 0;
}

如果你的项目中也有这样的布局,赶紧优化一下吧,当然仅限于“左上角”的标签,如果是其他方位的,按传统实现即可

完整 demo 可以访问以下任意链接:

三、文本重叠

有时候在做文本特效时,不可避免需要重叠文本,比如文本外描边效果

image.png

大家可能都知道,文本描边其实是居中描边

.text{
    -webkit-text-stroke: 6px rgb(51, 51, 51);
}

这样会带来一个问题,当描边慢慢变大时,会覆盖文字颜色

image.png

为了解决这个问题,我们需要用到两层文本,在底下放描边,上面放文本颜色,示意如下

Kapture 2023-02-24 at 10.57.04.gif

而这里两层重叠的文本就需要用到绝对定位了,假设HTML是这样的

<p class="text" data-title="前端侦探">前端侦探</p>

这里加另一个data-title属性,用来生成伪元素,关键实现如下

.text::before{
    content: attr(data-title);
    position: absolute;
}

只需要将::before设置绝对定位即可,注意是::before,无需任何其他偏移属性,文本就默认重叠了,而且由于是绝对定位,层级也自动变高

从这里也可以看出,在绝对定位中,::before要比::after要好用的多!

关于文本修饰效果可以参考以前这篇文章:CSS和SVG实现文字渐变、描边、投影

完整 demo 可以访问以下任意链接:

四、多个元素水平垂直堆叠居中

再来看一个这样的例子,有多个尺寸不定的元素或者图片,需要堆叠居中,示意如下

image.png

最简单的方式就是,父容器设置flex居中特性,然后子元素直接设置绝对定位,关键实现如下

.wrap{
  display: flex;
  justify-content: center;
  align-items: center;
}
.item{
  position: absolute;
}

原因在于,本身元素是居中的,设置绝对定位后,仅仅不占空间而已,所以后面的元素会堆叠上来而不挤压,特别适合图片堆叠展示的效果

完整 demo 可以访问以下任意链接:

五、自定义水平方向点击范围

还记得之前这篇文章吗?CSS 实现树状结构目录

里面有个小细节也用到了绝对定位,非常巧妙,下面简单回顾一下:

假设HTML是这样的

<details>
  <details>
    <summary>
      <span class="tree-item">文件夹1-1</span>
    </summary>
    <details>
      <summary>
        <span class="tree-item">文件夹1-1-2</span>
      </summary>
    </details>
    <details>
      <summary>
        <span class="tree-item">文件夹1-1-3</span>
      </summary>
      <details>
        <summary>
          <span class="tree-item">文件夹1-1-3-1</span>
        </summary>
      </details>
      <details>
        <summary>
          <span class="tree-item">文件夹1-1-3-2</span>
        </summary>
      </details>
    </details>
  </details>
</details>

树形结构有一个明显的缩进层级关系,这里是通过内边距实现的

details{
  padding-left: 10px
}

image.png

有个问题是,由于是逐层嵌套结构,导致 层级越深,点击范围越小,就像这样

Kapture 2022-04-10 at 19.22.22.gif

那么,如何做成通栏都可以点击呢?

这时,我们可以创建一个伪元素,并设置绝对定位,但是只需要设置水平方向上的偏移量,这样在水平方向上位置就是固定的(相对于外层父级),而垂直方向上,仍然处于默认位置,也就是跟随容器本身,关键实现如下

.tree{
  /*最外层父级需要设置相对定位*/
  position: relative;
}
.tree-item::before{
    content: '';
    position: absolute;
    left: 10px;
    right: 10px;/*水平方向的尺寸依赖于父级.tree*/
    height: 38px;
    background: #EEF2FF;
    border-radius: 8px;
    z-index: -1;
    opacity: 0;
    transition: .2s;
}
.tree-item:hover::before{
    opacity: 1;
}

效果是这样的

Kapture 2022-04-10 at 20.02.48.gif

这样就非常完美了,而且除了这种方式,好像找不到其他更好的解决方案了,有其他解决方案欢迎留言讨论

完整 demo 可以访问以下任意链接:

六、最后总结一下

举了这么多例子,其实无非就是想强调一下,在使用绝对定位时并不一定需要left或者top这样的偏移量,不仅代码更加精简,有时还能达到意想不到的效果,下面总结一下

  1. 绝对布局的特性是不占空间,但不一定完全脱离文档流,只有在设置了偏移时才会脱离文档流
  2. 如果只设置了一个方向上的偏移量,那么在另外一个方向上仍然保留着文档流特性
  3. 在绝对定位中,::before要比::after要好用的多,因为::before默认就是初始位置,可以很轻易的实现重叠效果

然后就是实战了,根据上面这些案例,相信大家对绝对定位一定有了新的认识,多多使用吧~最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤

欢迎关注我的公众号:前端侦探