close

前言

這是用 CSS 對 JS 功能實現了一遍?今日前端早讀課文章由閱文 @XboxYan 授權,公號:前端偵探分享。

@XboxYan,閱文體驗設計部,專注用戶體驗相關,熱愛 CSS,熱愛原生,歡迎關注 github:https://github.com/XboxYan

正文從這開始~~

很多時候都會碰到字符串補全的需求,典型的例子就時間或者日期中的補零操作,例如

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」

接下來,給元素設置一個固定寬度,這裡由於是等寬字體,所以可以直接設置為 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 :https://codepen.io/xboxyan/pen/YzEdbwj

五、總結一下

以上介紹了 3 種 CSS 字符串補全方法,是不是又學到了幾個小技巧呢?這幾個方法各有千秋,比較一下各自優缺點:

第一種方案非常容易理解,也容易擴展,如果需要補全 3 位,只需要改變整體寬度即可,不足之處在於依賴等寬字體。

第二種方案比較符合 JS 邏輯,比較靈活,不足在於計算比較囉嗦,而且還要考慮 CSS 取值的容錯性。

第三種方案是我比較推薦的了,無需計算,也不依賴布局,可能知道的同學不多,而且如果要自定義計數器,兼容性有點差。

關於 CSS 實現的優點,有很多,比如更容易維護、幾乎不會報錯、代碼更加簡潔等等,如果你學會了,趕緊在項目中用起來吧。

關於本文作者:@XboxYan原文:https://segmentfault.com/a/1190000041580205

關於【CSS】相關推薦,歡迎讀者自薦投稿,前端早讀課等你來。+v:zhgb_f2er【第2752期】CSS 有了:has偽類可以做些什麼?【第2751期】用 CSS 來偷數據 - CSS injection(下)

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()