CSS 實現頭像名稱首字元自動佔位

XboxYan發表於2022-06-06

在 web 中經常會見到這樣的設計,很多 UI 元件庫也稱之為 Avator 元件,也就是頭像的意思,當頭像未設定時,會顯示名稱的首字元充當預設頭像,如下所示:

image-20220425163700684

實際效果可以檢視CSS avator(codepen.io),那麼如何通過 CSS 實現這一效果呢?

一、圖片載入失敗時的佔位

現代瀏覽器(Chrome、Firefox) img 標籤都支援偽元素了,不過只有當圖片載入失敗的時候才能看到

<img class="avator" src="https://tva1.sinaimg.cn/large/008i3skNgy1grgo8qjty1j30e80e8aad.jpg">
<img class="avator" src="">
.avator::before{
  content: '我是偽元素';
  color: red;
}

效果如下

image-20220426144838943

有了偽元素,要做一些事情就很方便了,比如將預設的“佔點陣圖”擠出去,設定偽元素高度為100%就行了,同時設定超出隱藏

.avator{
  width: 40px;
  height: 40px;
  overflow: hidden; /*記得超出隱藏*/
}
.avator::before{
  content: '';
  display: flex;
  background: bisque;
  height: 100%;
}

效果如下

image-20220425232506352

二、alt 首字元佔位

一般在使用 img 標籤時都推薦加上 alt 屬性,用來描述圖片資訊,也非常符合語義化。

<img class="avator" src="" alt="xboxyan">

然後在圖片載入失敗時,可以通過 attr獲取到完整的 alt 資訊

.avator::before{
  content: attr(alt); /* 獲取 alt 屬性 */
  color: rgb(250, 84, 28);
}

為了方便演示,這裡暫時把超出隱藏開啟

image-20220426150506684

那麼,如何只顯示第一個字元呢?

嘗試了一下::first-letter,發現不起作用,偽元素裡面不能再用偽元素了

.avator::before::first-letter{
  /*無效*/
}

需要換一種思路,比如增加字元間距,讓其餘字元都處於容器之外

.avator::before{
  /**/
  letter-spacing: 40px;
}

效果如下

image-20220426151053506

這樣一來,首字元“x”確實處於視線之中了。

不過新問題也來了,如何讓首字元水平垂直居中呢?

三、首字元水平垂直居中

垂直居中比較好辦。設定行高就行了

.avator::before{
  /**/
  line-height: 40px;
}

image-20220426151907447

水平居中貌似有些棘手,不過發揮你的奇思妙想,問題還是可以解決的!

首先,由於寬度限制,可以把所有的字元強制換行,保證每個字元都處於單獨一行,首行也不另外

.avator::before{
  /**/
  word-break: break-all; /*換行*/
}

image-20220426152524997

前面我們加了一個字元間距,但是字元間距是跟隨在字元後面的,所以第一個字元的前面是沒有間距的。為了保持首行左右平衡,所以手動加上同樣的間距,這裡採用text-indent來實現

.avator::before{
  /**/
    text-indent: 40px; /*首行縮排*/
}

image-20220426154513657

這樣對於首行來說,其實是左右邊距是一樣的。接下來,通過 flex 佈局居中就可以了

.avator::before{
  /**/
  display: flex;
  justify-content: center; /*水平居中*/
}

image-20220426154713560

對於英文字母來說,可能需要轉成大寫

.avator::before{
  /**/
  text-transform: capitalize; /*首字母大寫*/
}

然後超出隱藏看看效果吧

image-20220426155227128

四、特殊符號的影響

後來測試中,發現了另外一個問題,當 alt 中有一些特殊標點符號時,首字元會消失不見

<img class="avator" src="" alt="xboxyan(測試)">

開啟隱藏其實是這樣的

image-20220426160345500

是不是看著一團糟?其實就是一些閉尾標點惹的禍!比如這裡的(,預設情況下是不允許出現在一行的末尾的,所以強制換到了下一行,導致整個佈局錯亂。為了解決這個問題,可以使用一個比較冷門的 CSS 屬性 line-break - CSS(層疊樣式表) | MDN (mozilla.org) 來解決,有興趣的可以參考張鑫旭的這篇文章:CSS line-break屬性與中文標點換行

.avator::before{
  /**/
  line-break: anywhere; /*任意地方都換行*/
}

這下就沒問題了,都是整整齊齊的換行~

image-20220426162311447

下面整理一下,附上完整程式碼

<ul class="list">
  <li class="item">
    <img class="avator" src="https://tva1.sinaimg.cn/large/008i3skNgy1grgo8qjty1j30e80e8aad.jpg" alt="xboxyan">
    xboxyan
  </li>
  <li class="item">
    <img class="avator" src="" alt="xboxyan">
    xboxyan
  </li>
  <li class="item">
    <img class="avator" src="" alt="前端偵探">
    前端偵探
  </li>
  <li class="item">
    <img class="avator" src="" alt="體驗設計部">
    體驗設計部
  </li>
</ul>
.list{
  list-style: none;
  padding: 0;
}
.avator{
  width: 40px;
  height: 40px;
  border-radius: 8px;
  overflow: hidden;
  background: bisque;
}
.avator::before{
  content: attr(alt);
  display: flex;
  width: 100%;
  height: 100%;
  background-color: bisque;
  text-transform: uppercase;
  line-height: 40px;
  letter-spacing: 40px;
  text-indent: 40px;
  justify-content: center;
  text-align: center;
  /* word-break: break-all; */
  line-break: anywhere;
  color: rgb(250, 84, 28);
}
.item{
  display: flex;
  align-items: center;
  gap: 15px;
  height: 64px;
  font-size: 18px;
}

效果如文章開頭所示,有需要的可以直接用起來了

image-20220425163700684

或者訪問線上連結 CSS avator(codepen.io) 或者 CSS avator (juejin.cn)

五、總結一下

以上就是本文的全部內容了,非常簡單實用的一個小功能,下面簡單總結一下

  1. 現代瀏覽器支援 img 偽元素了,並且只有在資源載入失敗時才可用,利用這一點可以設定圖片佔位符
  2. 偽元素通過 attr 屬性可以獲取 img 標籤屬性,推薦使用 alt
  3. 偽元素不能再使用偽類了
  4. 增加字元的行間距可以在可視範圍內僅看到一個字元
  5. 垂直居中可以通過行高來實現
  6. 水平居中可以通過首行縮排 和 flex 居中實現
  7. 部分特殊符號由於“避尾”或者“避首”特性,導致換行佈局錯亂
  8. line-break 可以打破以上規則

唯一的遺憾就是 Safari 不支援圖片偽元素,不過沒關係,不影響功能,也可以學到一些你可能不知道的小技巧。最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發❤❤❤

相關文章