歡迎關注我的公眾號:前端偵探
很多時候都會碰到字串補全的需求,典型的例子就時間或者日期中的補零操作,例如
2021-12-31
2022-03-03
通常的做法是
if (num < 10) {
num = '0' + num
}
後來,JS 中出現了原生的補全方法padStart()
和padEnd()
,如下
'3'.padStart(2, '0')
// 結果是 ’03‘
'12'.padStart(2, '0')
// 結果是 ’12‘
其實呢,在 CSS 中也是可以實現這樣的效果的,並且有多種方案,下面一起看看吧,相信能有不一樣的體會
一、flex-end 對齊
先介紹一個比較容易理解的方案,也非常簡單,假設 HTML 是這樣的
<span>2</span>
-
<span>28</span>
一般情況下,還會設定等寬字型,看起來更加協調、美觀
span{
font-family: Consolas, Monaco, monospace;
}
我們需要在數字前用偽元素生成一個“0”
span::before{
content: '0'
}
接下來,給元素設定一個固定寬度,這裡由於是等寬字型,所以可以直接設定為2ch
,注意這個ch
單位,它表示字元0
的寬度(有興趣的可以參考這篇文章:等寬字型在web佈局中應用以及CSS3 ch單位嘿嘿),然後設定右對齊就行了
span{
/**/
display: inline-flex;
width: 2ch;
justify-content: flex-end;
}
原理很簡單,在 2 個字元寬度的空間裡放置 3 個字元,以右對齊的方式,是不是就自動把最左邊的 0 給擠出去了?然後超出隱藏就可以了
完整程式碼如下
span::before{
content: '0'
}
span{
display: inline-flex;
width: 2ch;
justify-content: flex-end;
overflow: hidden;
}
二、CSS 變數動態計算
由於 CSS 無法獲取標籤的文字內容,所以這裡需要構建一個 CSS 變數傳遞下去,如下
<span style="--num:2">2</span>
-
<span style="--num:12">28</span>
通過 var(--num)
拿到變數以後,就可以進行一系列的邏輯判斷了,那麼,如何在小於 10 的情況下自動補零呢?
同樣我們需要在數字前用偽元素生成一個“0”
span::before{
content: '0'
}
然後,只需要根據 CSS 變數動態隱藏這個偽元素就行了,先設定透明度,如下
span::before{
/**/
opacity: calc(10 - var(--num));
}
效果如下
具體的邏輯就是
- 當
--num
等於 10 時,透明度的計算值就是 0,直接按照 0 來渲染 - 當
--num
大於 10 時,透明度的計算值就是負數值,會按照 0 來渲染 - 當
--num
小於 10 時,透明度的計算值就是大於等於1的值,會按照 1 來渲染
所以,最終的表現就是當大於等於10時不可見,小於10的時候可見
但是,這樣還是有點問題的,透明度不會影響元素的位置,如下
如何消除這個位置呢?方法有很多,這裡採用 margin-left
的方式,如下
span::before{
/**/
margin-left: clamp(-1ch, calc((9 - var(--num)) * 1ch),0ch);
}
這裡用到了clamp,你可以理解為一個區間,有 3 個值 [Min, Val, Max]
,前後分別是最小、最大值,中間是可變值(注意這裡是和 9 比較),所以這裡的邏輯就是
- 當
--num
大於等於 10 時,假設為 15,中間 calc 值計算為 -5ch,clamp 取值為最小值 -1ch - 當
--num
小於 10 時,假設為 5,中間 calc 值計算為 5ch,clamp 取值為最大值 0ch
所以,最終的表現就是當大於等於10時margin-left為-1ch,小於10的時候margin-left為0
這樣就比較完美了
完整程式碼如下
span::before{
content: '0';
opacity: calc(10 - var(--num));
margin-left: clamp(-1ch, calc((9 - var(--num)) * 1ch),0ch);
}
三、定義計數器樣式
利用計數器也能實現這一效果,首先看預設的計數器效果,我們需要隱藏原有的文字,利用計數器讓 CSS 變數通過偽元素展示出來,關於這個技巧,可以參考這篇文章:小tips: 如何藉助content屬性顯示CSS var變數值,如下
span::before{
counter-reset: num var(--num);
content: counter(num);
}
接下來需要用到 counter
的第 2 個引數 <counter-style>,計數器樣式。這是幹什麼的呢?相信大家都用過一個屬性 list-style-type,就是和這個相通的,可以定義序列的樣式,比如按照小寫英文字母的順序
list-style-type: lower-latin;
這裡我們需要一個 10 以內自動補零的計數器,剛好有個現成的,叫做 decimal-leading-zero
,翻譯過來就是,十進位制前置零
list-style-type: decimal-leading-zero;
回到這裡,需要做的就很簡單了,補上這個引數就行了,完整程式碼如下
span::before{
counter-reset: num var(--num);
content: counter(num, decimal-leading-zero);
}
效果如下
四、計數器的擴充套件
上面的計數器只適用於2位數的,如果需要 3 位數的怎麼辦呢? 例如
001、002、...、010、012、...、098、099、100
JS 中的 padStart
可以指定填充後的位數
'1'.padStart(3, '0')
// 結果是 ’001‘
'99'.padStart(3, '0')
// 結果是 ’099‘
'101'.padStart(3, '0')
// 結果是 ’101‘
其實,CSS 中也是有這樣的能力的,叫做@counter-style/pad,嚴格來說,這才是官方的補全方案,語法也非常類似
pad: 3 "0";
但是,這個需要用在自定義計數器上,也就是@counter-style,有興趣的可以參考張老師的這篇文章:CSS @counter-style規則詳細介紹,這裡簡單介紹一下用法,假設定義一個計數器叫做pad-num
,實現如下
@counter-style pad-num {
system: extends numeric;
pad: 3 "0";
}
語法是這樣的:這裡的system
表示“系統”,就是內建的一些計數器,比如這裡用到了extends numeric
,後面的numeric
表示數字技術系統,前面的extends
表示擴充套件,以這個為基礎,然後pad: 3 "0"
就和 JS 的意義一樣了,表示不足 3 位的地方補“0”
然後運用到計數器中:
span::before{
counter-reset: num var(--num);
content: counter(num, pad-num);
}
效果如下:
當然,這個相容性略差,根據實際需求即可
以上完整程式碼可以訪問 CSS pad(codepen.io)
五、總結一下
以上介紹了3種 CSS 字串補全方法,是不是又學到了幾個小技巧呢?這幾個方法各有千秋,比較一下各自優缺點:
- 第一種方案非常容易理解,也容易擴充套件,如果需要補全 3 位,只需要改變整體寬度即可,不足之處在於依賴等寬字型。
- 第二種方案比較符合 JS 邏輯,比較靈活,不足在於計算比較囉嗦,而且還要考慮 CSS 取值的容錯性。
- 第三種方案是我比較推薦的了,無需計算,也不依賴佈局,可能知道的同學不多,而且如果要自定義計數器,相容性有點差。
關於 CSS 實現的優點,有很多,比如更容易維護、幾乎不會報錯、程式碼更加簡潔等等,如果你學會了,趕緊在專案中用起來吧。最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發❤❤❤
歡迎關注我的公眾號:前端偵探