CSS 數(shù)學(xué)函數(shù)與容器查詢實現(xiàn)不定寬文本溢出跑馬燈效果
在許久之前,曾經(jīng)寫過這樣一篇文章 -- 不定寬溢出文本適配滾動[1]。我們實現(xiàn)了這樣一種效果:
文本內(nèi)容不超過容器寬度,正常展示 文本內(nèi)容超過容器的情況,內(nèi)容可以進(jìn)行跑馬燈來回滾動展示
像是這樣:

但是,之前的方案,有一個很明顯的缺點,如果我們事先知道了容器的寬度,那么沒問題,但是如果沒法確定容器的寬度,也就文本寬度不確定,容器寬度也不確定的話,那么整個效果會有一點瑕疵。
瑕疵在于,當(dāng)時的 CSS 技術(shù),其實沒法判斷當(dāng)前文本內(nèi)容長度是否超過了其容器寬度,導(dǎo)致即便文本沒有沒有超長,Hover 上去也會進(jìn)行一個來回滾動,像是這樣:

容器查詢 cqw 和 CSS 數(shù)學(xué)函數(shù) max
背景描述大概是這樣,感興趣的同學(xué),可以簡單翻看一下上午提到的文章 -- 不定寬溢出文本適配滾動[2]。
到今天,我們重新審視這個問題??纯吹浇裉?,我們可以如何更加簡單便捷的解決這個問題!
首先,我們的問題其實可以抽象成:
判斷文本寬度與容器寬度的大小差異,文本寬度是否大于容器寬度 如果超出,則設(shè)置來回位移動畫,位移的幅度為容器寬度與文本寬度的差值
那么,我們一步一步來。
假設(shè)我們的 HTML 結(jié)構(gòu)如下:
<div class="marquee">
<span>Lorem ipsum dolor sit amet elit. Animi, aliquid.<span>
</div>
其中,div 為容器,span 為文本內(nèi)容。同時,我們利用容器查詢,設(shè)置父容器 marquee 為容器查詢的容器,并且將基于容器的inline-size 維度。
.marquee {
white-space: nowrap;
container-type: inline-size;
}
繼續(xù),我們?nèi)绾文軌蛟?span 中得知,當(dāng)前 span 的內(nèi)容長度與父容器寬度誰比較大呢?
在之前,這是很難辦到的,但是現(xiàn)在,我們有了 容器查詢 后,可以靠容器查詢單位 cqw 完成。
首先,什么是容器查詢?容器查詢它給予了 CSS,在不改變?yōu)g覽器視口寬度的前提下,只是根據(jù)容器的寬度變化,對布局做成調(diào)整的能力。
對容器查詢想了解更多的,可以戳:新時代布局新特性 -- 容器查詢[3]
容器查詢帶來了很多新的單位,其中有:
cqw 容器查詢寬度(Container Query Width)占比。1cqw 等于容器寬度的 1%。假設(shè)容器寬度是 1000px,則此時 1cqw 對應(yīng)的計算值就是 10px。 cqh 容器查詢高度(Container Query Height)占比。1cqh 等于容器高度的 1%。 cqi 表示容器查詢內(nèi)聯(lián)方向尺寸(Container Query Inline-Size)占比。這個是邏輯屬性單位,默認(rèn)情況下等同于 cqw cqb 容器查詢塊級方向尺寸(Container Query Block-Size)占比。同上,默認(rèn)情況下等同于 cqh cqmin 容器查詢較小尺寸的(Container Query Min)占比。取 cqw 和 cqh 中較小的一個 cqmax 表示容器查詢較大尺寸的(Container Query Min)占比。取 cqw 和 cqh 中較大的一個
本文,我們會運用到其中的 cqw,1cqw 等于容器寬度的 1%。那么,當(dāng)前容器的寬度,其實就是 100 cqw。
那么:
width: 100%,對于 span 行內(nèi)元素而言,其文本長度就是其整個的寬度,100% 代表的就是文本內(nèi)容的長度width: 100cqw表示的是設(shè)置了容器查詢的.marquee的寬度(也就是父容器的寬度)
OK,有了 100% 和 100cqw 怎么比較他們誰大誰小呢?其實我們的關(guān)鍵不是誰大誰小,而是:
如果當(dāng)前容器的寬度(也就是文本寬度)大于父容器寬度,需要得到一個動畫位置值 如果當(dāng)前容器的寬度(也就是文本寬度)小于父容器寬度,無需動畫,也就是動畫位移值為 0
那么,我們的核心就變成了,0 與兩個寬度差值的比較。剛好,CSS 中提供了比較大小數(shù)學(xué)函數(shù) max() 和 min()。
關(guān)于 CSS 數(shù)學(xué)函數(shù),你可以參考我的這篇文章 -- 現(xiàn)代 CSS 解決方案:CSS 數(shù)學(xué)函數(shù)[4]
鋪墊了這么久,最終,我們得到最為核心的一行代碼:
max(100% - 100cqw, 0px)
當(dāng)然,換一種思維,使用 min() 也是可以的:
min(100cqw - 100%, 0px)
如果 span 內(nèi)容長度,大于容器寬度,也就是 100% - 100cqw 大于 0px,那么其實也就得到了跑馬燈效果應(yīng)該位移的距離。
我們順便也就將整個效果的代碼寫完了,完整的代碼:
.marquee {
overflow: hidden;
white-space: nowrap;
width: 200px;
resize: horizontal;
container-type: inline-size;
}
.marquee span {
animation: marquee 3s linear infinite both alternate;
}
@keyframes marquee {
to {
transform: translateX(min(100cqw - 100%, 0px));
}
}
效果如下:

這樣,到今天,我們可以輕易的實現(xiàn):
文本內(nèi)容不超過容器寬度,正常展示 文本內(nèi)容超過容器的情況,內(nèi)容可以進(jìn)行跑馬燈來回滾動展示
也就是如下的效果:

完整的代碼,你可以戳這里:Pure CSS Marquee[5]
當(dāng)然,硬要說的話,本方案還是存在一個缺陷,就是動畫的時長是固定的,沒法根據(jù)內(nèi)容的長短響應(yīng)式的進(jìn)行適配??赡芨m合文本內(nèi)容相差不大的場景使用。
最后
本案例 DEMO 由日服第一切圖仔佐子哥[6]傾情貢獻(xiàn)。
好了,本文到此結(jié)束,希望本文對你有所幫助 :)
如果還有什么疑問或者建議,可以多多交流,原創(chuàng)文章,文筆有限,才疏學(xué)淺,文中若有不正之處,萬望告知。
參考資料
不定寬溢出文本適配滾動: https://github.com/chokcoco/iCSS/issues/81
[2]不定寬溢出文本適配滾動: https://github.com/chokcoco/iCSS/issues/81
[3]新時代布局新特性 -- 容器查詢: https://github.com/chokcoco/iCSS/issues/201
[4]現(xiàn)代 CSS 解決方案:CSS 數(shù)學(xué)函數(shù): https://github.com/chokcoco/iCSS/issues/177
[5]Pure CSS Marquee: https://codepen.io/wheatup/pen/ZEMGaKw
[6]佐子哥: https://codepen.io/wheatup
