現(xiàn)代 CSS 解決方案:數(shù)學(xué)函數(shù)之 Min、Max、Clamp
在 CSS 中,其實(shí)存在各種各樣的函數(shù)。具體分為:
- Transform functions[1]
- Math functions[2]
- Filter functions[3]
- Color functions[4]
- Image functions[5]
- Counter functions[6]
- Font functions[7]
- Shape functions[8]
- Reference functions[9]
- CSS grid functions[10]
本文,將具體介紹其中的 CSS 數(shù)學(xué)函數(shù)(Math functions)中,已經(jīng)被瀏覽器大規(guī)模支持的 4 個(gè):
- calc()
- min()
- max()
- clamp()
為什么說是被瀏覽器大規(guī)模支持的?因?yàn)槌诉@ 4 個(gè)目前已經(jīng)得到大規(guī)模支持的數(shù)學(xué)函數(shù)外,其實(shí)規(guī)范 CSS Values and Units Module Level 4[11] 已經(jīng)定義了諸如三角函數(shù)相關(guān) sin()、cos()、tan() 等,指數(shù)函數(shù)相關(guān) pow()、sqrt() 等等數(shù)學(xué)函數(shù),只是目前都處于實(shí)驗(yàn)室階段,還沒有瀏覽器支持它們,需要給時(shí)間一點(diǎn)時(shí)間。
上一篇文章我們?cè)敿?xì)講述了 calc(),本文我們將探討一下另外 3 個(gè)。關(guān)于 calc(),你可以戳這里:
現(xiàn)代 CSS 解決方案:CSS 數(shù)學(xué)函數(shù)之 calc。
min()、max()、clamp()
min()、max()、clamp() 適合放在一起講。它們的作用彼此之間有所關(guān)聯(lián)。
- max():從一個(gè)逗號(hào)分隔的表達(dá)式列表中選擇最大(正方向)的值作為屬性的值。
- min():從一個(gè)逗號(hào)分隔的表達(dá)式列表中選擇最小的值作為屬性的值。
- clamp():把一個(gè)值限制在一個(gè)上限和下限之間,當(dāng)這個(gè)值超過最小值和最大值的范圍時(shí),在最小值和最大值之間選擇一個(gè)值使用。
由于在現(xiàn)實(shí)中,有非常多元素的的屬性不是一成不變的,而是會(huì)根據(jù)上下文、環(huán)境的變化而變化。
譬如這樣一個(gè)布局:
<div class="container"></div>
.container {
height: 100px;
background: #000;
}
效果如下,.container 塊它會(huì)隨著屏幕的增大而增大,始終占據(jù)整個(gè)屏幕:
對(duì)于一個(gè)響應(yīng)式的項(xiàng)目,我們肯定不希望它的寬度會(huì)一直變大,而是當(dāng)達(dá)到一定的閾值時(shí),寬度從相對(duì)單位變成了絕對(duì)單位,這種情況就適用于 min(),簡單改造下代碼:
.container {
width: min(100%, 500px);
height: 100px;
background: #000;
}
容器的寬度值會(huì)在 width: 100% 與 width: 500px 之間做選擇,選取相對(duì)小的那個(gè)。
在屏幕寬度不足 500px 時(shí)候,也就表現(xiàn)為 width: 100%,反之,則表現(xiàn)為 width: 500px:
同理,在類似的場(chǎng)景,我們也可以使用 max() 從多個(gè)值中,選取相對(duì)更大的值。
min()、max() 支持多個(gè)值的列表
min()、max() 支持多個(gè)值的列表,譬如 width: max(1px, 2px, 3px, 50px)。
當(dāng)然,對(duì)于上述表達(dá):
width: max(1px, 2px, 3px, 50px) 其實(shí)等于 width: 50px。因此,對(duì)于 min()、max() 的具體使用而言,最多應(yīng)該只包含一個(gè)具體的絕對(duì)單位。否則,這樣的像上述這種代碼,雖然語法支持,但是任何情況下,計(jì)算值都是確定的,其實(shí)沒有意義。
配合 calc
min()、max()、clamp() 都可以配合 calc 一起使用。
譬如:
div {
width: max(50vw, calc(300px + 10%));
}
在這種情況下,calc 和相應(yīng)包裹的括號(hào)可以省略,因此,上述代碼又可以寫成:
div {
width: max(50vw, 300px + 10%);
}
基于 max、min 模擬 clamp
現(xiàn)在,有這樣一種場(chǎng)景,如果,我們又需要限制最大值,也需要限制最小值,怎么辦呢?
像是這樣一個(gè)場(chǎng)景,**字體的大小,最小是 12px,隨著屏幕的變大,逐漸變大,但是為了避免老人機(jī)現(xiàn)象(隨著屏幕變大,無限制變大),我們還需要限制一個(gè)最大值 20px。
我們可以利用 vw 來實(shí)現(xiàn)給字體賦動(dòng)態(tài)值,假設(shè)在移動(dòng)端,設(shè)備寬度的 CSS 像素為 320px 時(shí),頁面的字體寬度最小為 12px,換算成 vw 即是 320 / 100 = 3.2,也就是 1vw 在 屏幕寬度為 320px 時(shí)候,表現(xiàn)為 3.2px,12px 約等于 3.75 vw。
同時(shí),我們需要限制最大字體值為 20px,對(duì)應(yīng)的 CSS 如下:
p {
font-size: max(12px, min(3.75vw, 20px));
}
看看效果:
通過 max()、min() 的配合使用,以及搭配一個(gè)相對(duì)單位 vw,我們成功地給字體設(shè)置了上下限,而在這個(gè)上下限之間實(shí)現(xiàn)了動(dòng)態(tài)變化。
當(dāng)然,上面核心的這一段 max(12px, min(3.75vw, 20px)) 看上去有點(diǎn)繞,因此,CSS 推出了 clamp() 簡化這個(gè)語法,下面兩個(gè)寫法是等價(jià)的:
p {
font-size: max(12px, min(3.75vw, 20px));
// 等價(jià)于
font-size: clamp(12px, 3.75vw, 20px);
}
clamp()
clamp() 函數(shù)的作用是把一個(gè)值限制在一個(gè)上限和下限之間,當(dāng)這個(gè)值超過最小值和最大值的范圍時(shí),在最小值和最大值之間選擇一個(gè)值使用。它接收三個(gè)參數(shù):最小值、首選值、最大值。
有意思的是,clamp(MIN, VAL, MAX) 其實(shí)就是表示 max(MIN, min(VAL, MAX))。
使用 vw 配合 clamp 實(shí)現(xiàn)響應(yīng)式布局
我們繼續(xù)上面的話題。
在不久的過去,移動(dòng)端的適配方面,使用更多的 rem 適配方案,可能會(huì)借助一些現(xiàn)成的庫,類似于 flexible.js、hotcss.js 等庫。rem 方案比較大的一個(gè)問題在于需要一段 JavaScript 響應(yīng)視口變化,重設(shè)根元素的 font-size,并且,使用 rem 多少有點(diǎn) hack 的感覺。
在現(xiàn)在,在移動(dòng)端適配,我們更為推崇的是 vw 純 CSS 方案,與 rem 方案類似,它的本質(zhì)也是頁面的等比例縮放。它的一個(gè)問題在于,如果僅僅使用 vw,隨著屏幕的不斷變大或者縮小,內(nèi)容元素將會(huì)一直變大變小下去,這也導(dǎo)致了在大屏幕下,許多元素看著實(shí)在太大了!
因此,我們需要一種能夠控制最大、最小閾值的方式,像是這樣:
此時(shí),clamp 就能非常好的派上用場(chǎng),還是我們上述的例子,這一段代碼 font-size: max(12px, min(3.75vw, 20px));,就能將字體限制在 12px - 20px 的范圍內(nèi)。
因此,對(duì)于移動(dòng)端頁面而言,所有涉及長度的單位,我們都可以使用 vw 進(jìn)行設(shè)置。而諸如字體、內(nèi)外邊距、寬度等不應(yīng)該完全等比例縮放的,采用 clamp() 控制最大最小閾值。
在 Modern Fluid Typography Using CSS Clamp[12] 一文中,對(duì)使用 clamp() 進(jìn)行流式響應(yīng)式布局還有更為深入的探討,感興趣的可以深入閱讀。
總結(jié)而言,對(duì)于移動(dòng)端頁面,我們可以以 vw 配合 clamp() 的方式,完成整個(gè)移動(dòng)端布局的適配。它的優(yōu)勢(shì)在于
- 沒有額外 JavaScript 代碼的引入,純 CSS 解決方案。
- 能夠很好地控制邊界閾值,合理的進(jìn)行縮放展示。
反向響應(yīng)式變化
還有一個(gè)技巧,利用 clamp() 配合負(fù)值,我們也可以反向操作,得到一種屏幕越大,字體越小的反向響應(yīng)式效果:
p {
font-size: clamp(20px, -5vw + 96px, 60px);
}
看看效果:
這個(gè)技巧挺有意思的,由于 -5vw + 96px 的計(jì)算值會(huì)隨著屏幕的變小而增大,實(shí)現(xiàn)了一種反向的字體響應(yīng)式變化。
總結(jié)
總結(jié)一下,合理運(yùn)用 min()、max()、clamp(),是構(gòu)建現(xiàn)代響應(yīng)式布局的重點(diǎn),我們可以告別傳統(tǒng)的需要 JavaScript 輔助的一些方案,基于 CSS 這些數(shù)學(xué)函數(shù)即可完成所有的訴求。
一些進(jìn)階閱讀非常好的文章:
- A guide to the min(), max(), and clamp() CSS functions[13]。
- Modern Fluid Typography Using CSS Clamp[14]。
最后
好了,本文到此結(jié)束,希望本文對(duì)你有所幫助 :)
參考資料
- [1]Transform functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#transform_functions。
- [2]Math functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#math_functions。
- [3]Filter functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#filter_functions。
- [4]Color functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#color_functions。
- [5]Image functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#image_functions。
- [6]Counter functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#counter_functions。
- [7]Font functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#font_functions。
- [8]Shape functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#shape_functions。
- [9]Reference functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#reference_functions。
- [10]CSS grid functions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#css_grid_functions。
- [11]CSS Values and Units Module Level 4: https://drafts.csswg.org/css-values/#math。
- [12]Modern Fluid Typography Using CSS Clamp: https://www.smashingmagazine.com/2022/01/modern-fluid-typography-css-clamp/。
- [13]A guide to the min(), max(), and clamp() CSS functions: https://blog.logrocket.com/min-max-clamp-css-functions/。
- [14]Modern Fluid Typography Using CSS Clamp: https://www.smashingmagazine.com/2022/01/modern-fluid-typography-css-clamp/。