聊聊有趣的 CSS 數(shù)學(xué)函數(shù)
今天來看看 CSS 中的數(shù)學(xué)函數(shù)。CSS 數(shù)學(xué)函數(shù)允許在 CSS 屬性值中執(zhí)行數(shù)學(xué)表達(dá)式。CSS 數(shù)學(xué)函數(shù)僅支持加法(+)、減法(-)、乘法(*)、除法(/)。目前在 CSS 中有四個得到很好支持的數(shù)學(xué)函數(shù):
- min():該函數(shù)允許你從逗號分隔符表達(dá)式中選擇一個最小值作為 CSS 的屬性值;
- max():該函數(shù)可以從一個逗號分隔的表達(dá)式列表中選擇最大(正方向)的值作為屬性的值;
- calc():該函數(shù)允許在聲明 CSS 屬性值時執(zhí)行一些計算;
- clamp():該函數(shù)的作用是把一個值限制在一個上限和下限之間,當(dāng)這個值超過最小值和最大值的范圍時,在最小值和最大值之間選擇一個值使用。它接收三個參數(shù):最小值、首選值、最大值。
這些 CSS 函數(shù)可能會以意想不到的方式使用,例如在漸變和顏色函數(shù)中以及與 CSS 自定義屬性結(jié)合使用。下面就來看看這四個CSS函數(shù)!
1. calc()
基本使用
calc() 函數(shù)有助于在 CSS 屬性值中執(zhí)行計算。它可以用在如下屬性中:length、frequency、angle、time、percentage、number、integer。
width: calc(100% - 80px);
calc() 函數(shù)用一個表達(dá)式作為它的參數(shù),用這個表達(dá)式的結(jié)果作為值。這個表達(dá)式可以是任何如下操作符的組合(+、-、*、/),采用標(biāo)準(zhǔn)操作符處理法則的簡單表達(dá)式。表達(dá)式中的運(yùn)算對象可以使用任意長度的值。如果你愿意,甚至可以在一個表達(dá)式中混用這類值的不同單位。在需要時,還可以使用小括號來建立計算順序。
該函數(shù)具有廣泛的用途,例如,如果希望某些內(nèi)容占據(jù)大部分視口高度。這時就可以使用相對的單位vh和絕對單位px進(jìn)行混合計算:
.content {
height: calc(100vh - 60px);
}
當(dāng)視口大小發(fā)生變化或者用戶使用較大或較小的設(shè)備時,100vh的值將動態(tài)更新,因此計算也將動態(tài)更新。使用calc() 的好處在于,它既可以避免添加一些 magic number,也可以避免使用 JavaScript 來計算樣式的屬性值。
生成調(diào)色板
我們可以通過傳入CSS自定義屬性來擴(kuò)展 calc() 的功能。一個非常有用的例子就是使用 hsl() (表示色調(diào)、飽和度和亮度)來創(chuàng)建一致的調(diào)色板。給定飽和度、亮度和起始色調(diào)的值,就可以使用 calc() 函數(shù)計算互補(bǔ)值來構(gòu)建完整的調(diào)色板。
.colors {
--base-hue: 140;
--saturation: 95%;
--lightness: 80%;
--rotation: 60;
color: #222;
text-align: center;
}
.color {
padding: 0.25rem;
background-color: hsl(var(--hue), var(--saturation), var(--lightness));
}
.color1 {
--hue: calc(var(--base-hue));
}
.color2 {
--hue: calc(var(--base-hue) + var(--rotation));
}
.color3 {
--hue: calc(var(--base-hue) + var(--rotation) * 2);
}
生成的調(diào)色板:
注意事項:
在使用 calc() 函數(shù)時需要注意:
- 「+ 和 - 運(yùn)算符的兩邊必須要有空白字符?!?比如,calc(50% -8px) 會被解析成為一個無效的表達(dá)式,解析結(jié)果是:一個百分比 后跟一個負(fù)數(shù)長度值。而加有空白字符的、有效的表達(dá)式 calc(8px + -50%)會被解析成為:一個長度 后跟一個加號 再跟一個負(fù)百分比。
和 / 這兩個運(yùn)算符前后不需要空白字符,但如果考慮到統(tǒng)一性,仍然推薦加上空白符。
- 用 0 作除數(shù)會使 HTML 解析器拋出異常。
- 涉及自動布局和固定布局的表格中的表列、表列組、表行、表行組和表單元格的寬度和高度百分比的數(shù)學(xué)表達(dá)式,auto 可視為已指定。
- calc() 函數(shù)支持嵌套,但支持的方式是:把被嵌套的 calc() 函數(shù)全當(dāng)成普通的括號。所以,函數(shù)內(nèi)直接用括號就好了。
瀏覽器兼容性
clac() 函數(shù)在這四個函數(shù)中具有最好的跨瀏覽器支持:
2. clamp()
基本使用
clamp() 的實際用途:在可接受的值范圍內(nèi)設(shè)置邊界。clamp() 被用在 length、frequency、angle、time、percentage、number、integer 屬性中。其語法如下:
clamp(MIN, VAL, MAX)
clamp(MIN, VAL, MAX) 其實就是表示 max(MIN, min(VAL, MAX))。clamp() 函數(shù)接收三個用逗號分隔的表達(dá)式作為參數(shù),按最小值、首選值、最大值的順序排列,這三個值的順序很重要。
- 當(dāng)首選值比最小值要小時,則使用最小值。
- 當(dāng)首選值介于最小值和最大值之間時,用首選值。
- 當(dāng)首選值比最大值要大時,則使用最大值。
這個表達(dá)式可以是數(shù)學(xué)函數(shù)、字面量或其它計算為有效的參數(shù)類型表達(dá)式,如 attr(),或嵌套的 min 和 max 。作為數(shù)學(xué)表達(dá)式,可以使用加減乘除運(yùn)算而無需使用 calc() 函數(shù)。也可以用括號來確定計算順序。表達(dá)式中的每一個值都可以用不同的單位。
來看下面的例子:
.element {
width: clamp(200px, 50%, 1000px);
}
有一個元素,其最小寬度為200px,首選值為50%,最大值為1000px。
這個元素的寬度永遠(yuǎn)不會低于200px,首選值是50%并且僅在視口寬度大于400px和小于2000px 時才有效,寬度不會超過1000px。
那 clamp() 是如何計算的呢?當(dāng) clamp() 用作值時,它等同于使用max()和min()函數(shù):
.element {
width: clamp(200px, 50%, 1000px);
width: max(200px, min(50%, 1000px));
}
這里的50%取決于瀏覽器視口寬度,假設(shè)視口寬度為1150px,解析的過程如下:
字體大小
假設(shè)需要要一個最小為16px,最大為50px的標(biāo)題。clamp()函數(shù)將給出一個介于兩者之間的值,而不會低于最小值或超過最大值。
.title {
font-size: clamp(16px, 5vw, 50px);
}
在這里使用clamp() 就非常完美,因為它可以確保使用的字體大小易于訪問和閱讀。如果要使用 min() 設(shè)置最大字體,就無法在小視口中控制字體。
.title {
font-size: min(3vw, 24px);
}
在移動視口中,字體很小。因此,不要只對字體大小使 min() 函數(shù)。當(dāng)然,也可以通過媒體查詢來取消或添加它。正如上面所說的,可以在 max() 函數(shù)中嵌套一個 min(),這將模擬clamp()函數(shù):
.title {
font-size: max(16px, min(10vw, 50px));
}
邊框和陰影
有時需要邊框?qū)挾群桶霃綉?yīng)該在移動設(shè)備上更小,通過使用 clamp() 就可以根據(jù)視口寬度來使它們動態(tài)變化。
.element {
box-shadow: 0 3px 10px 0 red;
border: min(1vw, 10px) solid #468eef;
border-radius: clamp(7px, 2vw, 20px);
box-shadow: 0 3px clamp(5px, 4vw, 50px) 0 rgba(0, 0, 0, 0.2);
}
Grid 間隙
當(dāng)使用 CSS Grid 布局時設(shè)置網(wǎng)格間隙,并且希望為移動視口縮小間隙。就可以使用 clamp():
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: clamp(1rem, 2vw, 24px);
}
注意事項
允許設(shè)置表達(dá)式的值為 max() 和 min() 。這些表達(dá)式是數(shù)學(xué)表達(dá)式,所以你可以進(jìn)行加減乘除運(yùn)算。
表達(dá)式可以是使用標(biāo)準(zhǔn)運(yùn)算符優(yōu)先規(guī)則組合 + 、- 、* 、/ 等運(yùn)算符的值,確保在 + 、- 兩側(cè)各有一個空格。表達(dá)式中的操作數(shù)可以是長度值??梢越o每一個值設(shè)置不同的單位。還可以用括號來確定計算順序。
瀏覽器兼容性
3. min()
基本使用
min() 函數(shù)方法接受一個或多個用逗號分隔的表達(dá)式作為他的參數(shù),數(shù)值最小的表達(dá)式的值將會作為指定的屬性的值。
min() 的實際用途:以包含元素響應(yīng)上下文的方式,在最大允許值上設(shè)置邊界。盡管是 min() 函數(shù),但結(jié)果是提供的值將作為屬性允許的最大值。
下面來看一個簡單的例子,希望元素的最大寬度為500px:
.element {
width: min(50%, 500px);
}
瀏覽器必須選擇最小的值(50%,500px)。選擇該選項取決于視口寬度。如果50%的計算值大于500px,那么它將被忽略,而使用500px。否則,如果50%的計算值小于500px,則50%將用作寬度值。視口寬度為1000px:
容器寬度
有一個容器的寬度是其父級寬度的80%,并且寬度不應(yīng)超過780px,那么該如何寫:
.container {
max-width: 780px;
width: 80%;
}
如果使用 min() 函數(shù),就可以這樣設(shè)置最大值,代碼簡潔了很多:
.container {
max-width: min(80%, 780px);
}
平滑漸變
在 CSS 中使用漸變時,可能需要通過使顏色之間的過渡更平滑一些來針對移動設(shè)備進(jìn)行一些調(diào)整。來看一個例子:
.element {
background: linear-gradient(135deg, #2c3e50, #2c3e50 60%, #3498db);
}
在移動設(shè)備中,這個顏色漸變就會有一條分割線,不是很好看。可以通過媒體查詢來解決這個問題:
@media (max-width: 700px) {
.element {
background: linear-gradient(135deg, #2c3e50, #2c3e50 25%, #3498db);
}
}
雖然這樣是可行的,但我們可以使用CSS 中的 min() 函數(shù)使這個顏色漸變更加動態(tài):
.element {
background: linear-gradient(135deg, #2c3e50, #2c3e50 min(20vw, 60%), #3498db);
}
這樣顏色漸變就看起來順滑了很多:
注意事項
- 表達(dá)式中的操作數(shù)可以是任何長度值。表達(dá)式中的每個值可以使用不同的單位。必要時,還可以使用括號來確定計算順序。
- 通常需要組合 min()和 max()的值,或者在 clamp() 或 calc() 函數(shù)中使用 min()。
- 如果需要應(yīng)用多個長度約束,則可以提供兩個以上的參數(shù)。
瀏覽器兼容性
4. max()
基本使用
max() 函數(shù)方法接受一個或多個用逗號分隔的表達(dá)式作為他的參數(shù),數(shù)值最大的表達(dá)式的值將會作為指定的屬性的值。
max() 的實際用途:以包含元素響應(yīng)上下文的方式,在最小允許值上設(shè)置邊界。
下面來看一個簡單的例子,通常,頁面的側(cè)邊欄有一個固定的寬度,而主寬度是靈活大小的。如果視口足夠大,可以使側(cè)邊欄更具動態(tài)性以占用更多空間。為此,需要使用 max() 函數(shù)為其設(shè)置「最小寬度?!?/p>
.wrapper {
display: flex;
}
aside {
flex-basis: max(30vw, 150px);
}
main {
flex-grow: 1;
}
側(cè)邊欄的最小寬度為150px,如果視口寬度大于500px(500*30%=150),則最小寬度為30vw。
瀏覽器兼容性
參考:
https://moderncss.dev/practical-uses-of-css-math-functions-calc-clamp-min-max/
https://ishadeed.com/article/css-min-max-clamp/