你可能不知道的絕對定位

分享一個關於絕對定位的實戰開發經驗。

在普遍的認知下,絕對定位好像都是伴隨着偏移屬性(left/right/top/bottom)一起出現的,相信大家都寫過這樣的CSS,如下

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

其實,有些情況下是可以不需要偏移量的,不僅實現上更加簡潔,適應性也更強,甚至還能實現加上偏移量反而實現不了的佈局,一起看看吧,相信會有不一樣的體會

一、絕對定位的特性

談到絕對定位佈局,大家可能會馬上就會想到這些特性:

第一條沒什麼問題,確實不會佔用空間。現在來看第二條,**真的完全脫離文檔流了嗎?**假設有這樣一個佈局

<p>
  歡迎關注前端偵探
</p>

然後生成一個僞元素,設置成絕對定位

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

在不設置任何偏移的情況下,可以看到,絕對定位元素始終跟隨在文本後面,也就是說,現在仍然處於文檔流中,如下

如果僅設置一個方向,比如left

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

那麼,在水平方向上,絕對定位元素始終位於最左邊,而垂直方向上,仍然保持着跟隨文檔的特性,只是單方向的

如果兩個方向上都設置了,這也是我們最常見的寫法

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

那麼,這個元素位置就完全固定了,真正的脫離了文檔流

綜上所述,絕對定位元素,只有在設置了偏移時纔會脫離文檔流,如果只設置了一個方向上的,那麼在另外一個方向上仍然保留着文檔流特性,或者這麼說,絕對定位元素仍然保持在原來的位置,並且不佔空間,除非設置了偏移纔會真正固定定位

瞭解了這些,下面來看幾個實際案例

二、左上角的標籤

大家可能經常會碰到這樣的 “角標” 效果

現在簡單實現一下,假設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的情況下,由於不佔空間,所以也不影響其他元素,效果如下

因此,像這種場景下,設置偏移量和父級定位可以說都是多餘的

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

如果你的項目中也有這樣的佈局,趕緊優化一下吧,當然僅限於 “左上角” 的標籤,如果是其他方位的,按傳統實現即可

完整 demo 可以訪問以下任意鏈接:

三、文本重疊

有時候在做文本特效時,不可避免需要重疊文本,比如文本外描邊效果

大家可能都知道,文本描邊其實是居中描邊

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

這樣會帶來一個問題,當描邊慢慢變大時,會覆蓋文字顏色

爲了解決這個問題,我們需要用到兩層文本,在底下放描邊,上面放文本顏色,示意如下

而這裏兩層重疊的文本就需要用到絕對定位了,假設HTML是這樣的

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

這裏加另一個data-title屬性,用來生成僞元素,關鍵實現如下

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

只需要將::before設置絕對定位即可,注意是::before,無需任何其他偏移屬性,文本就默認重疊了,而且由於是絕對定位,層級也自動變高

從這裏也可以看出,在絕對定位中,::before要比::after要好用的多!

關於文本修飾效果可以參考以前這篇文章:CSS 和 SVG 實現文字漸變、描邊、投影 [4]

完整 demo 可以訪問以下任意鏈接:

四、多個元素水平垂直堆疊居中

再來看一個這樣的例子,有多個尺寸不定的元素或者圖片,需要堆疊居中,示意如下

最簡單的方式就是,父容器設置flex居中特性,然後子元素直接設置絕對定位,關鍵實現如下

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

原因在於,本身元素是居中的,設置絕對定位後,僅僅不佔空間而已,所以後面的元素會堆疊上來而不擠壓,特別適合圖片堆疊展示的效果

完整 demo 可以訪問以下任意鏈接:

五、自定義水平方向點擊範圍

還記得之前這篇文章嗎?CSS 實現樹狀結構目錄 [11]

裏面有個小細節也用到了絕對定位,非常巧妙,下面簡單回顧一下:

假設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
}

有個問題是,由於是逐層嵌套結構,導致 層級越深,點擊範圍越小,就像這樣

那麼,如何做成通欄都可以點擊呢?

這時,我們可以創建一個僞元素,並設置絕對定位,但是只需要設置水平方向上的偏移量,這樣在水平方向上位置就是固定的(相對於外層父級),而垂直方向上,仍然處於默認位置,也就是跟隨容器本身,關鍵實現如下

.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;
}

效果是這樣的

這樣就非常完美了,而且除了這種方式,好像找不到其他更好的解決方案了,有其他解決方案歡迎留言討論

完整 demo 可以訪問以下任意鏈接:

六、最後總結一下

舉了這麼多例子,其實無非就是想強調一下,在使用絕對定位時並不一定需要left或者top這樣的偏移量,不僅代碼更加精簡,有時還能達到意想不到的效果,下面總結一下

  1. 絕對佈局的特性是不佔空間,但不一定完全脫離文檔流,只有在設置了偏移時纔會脫離文檔流

  2. 如果只設置了一個方向上的偏移量,那麼在另外一個方向上仍然保留着文檔流特性

  3. 在絕對定位中,::before要比::after要好用的多,因爲::before默認就是初始位置,可以很輕易的實現重疊效果

然後就是實戰了,根據上面這些案例,相信大家對絕對定位一定有了新的認識,多多使用吧~ 最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發❤❤❤

參考資料

[1]

CSS absolute tag (juejin.cn): https://code.juejin.cn/pen/7203544411974664224

[2]

CSS absolute tag (codepen.io): https://codepen.io/xboxyan/pen/wvEWRoJ

[3]

CSS absolute tag (runjs.work): https://runjs.work/projects/ce00c1830e6e47a9

[4]

CSS 和 SVG 實現文字漸變、描邊、投影: https://juejin.cn/post/7010944239609577508

[5]

CSS text stroke (juejin.cn): https://code.juejin.cn/pen/7203553341917298725

[6]

CSS text stroke (codepen.io): https://codepen.io/xboxyan/pen/rNZLoKP

[7]

CSS text stroke (runjs.work): https://runjs.work/projects/39c51954b6494e88

[8]

CSS absolute center (juejin.cn): https://code.juejin.cn/pen/7203558150899925050

[9]

CSS absolute center (codepen.io): https://codepen.io/xboxyan/pen/yLxJGwQ

[10]

CSS absolute center (runjs.work): https://runjs.work/projects/5a558fc986ae4fb1

[11]

CSS 實現樹狀結構目錄: https://juejin.cn/post/7095580369537204238

[12]

CSS tree (juejin.cn): https://code.juejin.cn/pen/7085639478659776542

[13]

CSS tree (codepen.io): https://codepen.io/xboxyan/pen/ExoRQNX

[14]

CSS tree (runjs.work): https://runjs.work/projects/949c2f2eacb94ff7

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/NdPPfn_W7NQZiYF5C5AeGw