if()
語法
/* Single <if-test> */
if(style(--scheme: dark): #eeeeee;)
if(media(print): black;)
if(media(width > 700px): 0 auto;)
if(supports(color: lch(7.1% 60.23 300.16)): lch(7.1% 60.23 300.16);)
/* <if-test> with else */
if(style(--size: "2xl"): 1em; else: 0.25em;)
if(media(print): white; else: black;)
if(media(width < 700px): 0 auto; else: 20px auto)
if(
supports(color: lch(7.1% 60.23 300.16)): lch(7.1% 60.23 300.16);
else: #03045e;
)
if(
supports(color: lch(75% 0 0)): 3px solid lch(75% 0 0);
else: 3px solid silver;
)
/* Multiple <if-test>s */
if(
style(--scheme: ice): linear-gradient(#caf0f8, white, #caf0f8);
style(--scheme: fire): linear-gradient(#ffc971, white, #ffc971);
else: none;
)
/* <if-test> within a shorthand */
3px yellow if(
style(--color: green): dashed;
style(--color: yellow): inset;
else: solid;
)
引數
引數是一個以分號分隔的 <if-branch> 列表。每個 <if-branch> 是一個 <if-condition>,後面跟著一個冒號和一個 <value>。
<if-branch> = <if-condition> : <value>;
返回值
一個值或保證無效值。
描述
CSS if() 函式為 CSS 屬性值提供了條件邏輯,其工作方式類似於 JavaScript 的 if...else 語句。
if() 函式可以在任何屬性的值中使用,並且可以包含零個或多個以分號分隔的 <if-condition>。每個 <if-condition> 要麼是一個 <if-test> : <value> 對,要麼是一個 else : <value> 對。最後一個 <if-condition> 後面的分號是可選的。
返回值按如下方式計算
<if-condition>表示式按照它們在函式中出現的順序進行評估。- 第一個評估為
true的<if-condition>將返回其關聯的<value>。 - 如果沒有
<if-condition>評估為true,則函式返回一個 <guaranteed-invalid>。如果在具有回退值的值語句中使用if()函式(例如自定義屬性或anchor()函式),這會表現為無效或false。
例如
div {
background-image: if(
style(--scheme: ice): linear-gradient(#caf0f8, white, #caf0f8);
style(--scheme: fire): linear-gradient(#ffc971, white, #ffc971);
else: none;
);
}
在這個例子中,我們根據 --scheme 自定義屬性是否設定為 ice 或 fire,為 <div> 元素的 background-image 設定不同的 linear-gradient()。如果 --scheme 不存在,或者存在但設定為任何其他值,則 else 值生效,background-image 屬性將被設定為 none。
備註: 每個條件必須用冒號與其關聯的值分隔開,並且每個 <if-condition> : <value> 對必須用分號分隔開。最後一個 <if-condition> : <value> 對的分號是可選的。
警告: if 和左括號(()之間不能有空格。否則,整個宣告將無效。
如果單個 <if-condition> 或 <value> 無效,它不會使整個 if() 函式無效;相反,解析器會繼續處理下一個 <if-condition> : <value> 對。如果沒有一個 <if-condition> 或 <value> 是有效的,函式將返回保證無效值。
else : <value> 對的頻率和位置
你可以在一個 if() 函式中包含多個 else : <value> 對,位置不限。然而,在大多數情況下,在分號分隔列表的末尾使用單個 else : <value> 對來提供預設值,如果沒有任何一個 <if-test> 評估為 true,則始終返回該預設值。
如果你在任何 <if-test> : <value> 對之前包含一個 else : <value> 對,其後的條件將不會被評估,因為 else 總是評估為 true。因此,下面的 if() 總是返回 none,而兩個 <if-test> : <value> 對永遠不會被評估。
div {
background-image: if(
else: none;
style(--scheme: ice): linear-gradient(#caf0f8, white, #caf0f8);
style(--scheme: fire): linear-gradient(#ffc971, white, #ffc971)
);
}
除錯一個行為不符合預期的值時,你可能希望將 else : <value> 放在值列表末尾以外的位置。在下面的例子中,我們試圖確定第一個 <if-test> : <value> 對是否正常工作。如果不是,else : <value> 對會返回一個 url("debug.png") 值,以顯示一張圖片,指示第一個 <if-test> : <value> 對需要修復。最後兩個 <if-test> : <value> 對同樣永遠不會被評估。
div {
background-image: if(
style(--scheme: ice): linear-gradient(#caf0f8, white, #caf0f8);
else: url("debug.png");
style(--scheme: fire): linear-gradient(#ffc971, white, #ffc971);
else: none;
);
}
請注意,如果 if() 函式只包含一個 else : <value> 對,或者什麼都不包含,它仍然是有效的。以下屬性值都是有效的。
background-color: if(else: yellow);
background-image: if();
這些函式並沒有什麼用。包含它們是為了證明其有效性。在這種情況下,background-color 值將始終設定為 yellow,而 background-image 將被設定為其初始值。你最好直接將 background-color 設定為 yellow,將 background-image 設定為 initial 或 none。
if-test 的型別
<if-test> 接受三種查詢型別之一。本節將詳細介紹每一種。
樣式查詢
一個樣式查詢 <if-test> 允許你測試某個元素上是否設定了特定的屬性值,並因此為另一個屬性應用一個值。我們之前已經看過幾個樣式查詢的例子;讓我們再看一個例子。
background-image: if(
style(--scheme: ice): linear-gradient(#caf0f8, white, #caf0f8);
else: none;
);
如果在同一個元素上 --scheme 自定義屬性被設定為 ice,則返回提供的 linear-gradient() 值。如果不是,則返回 none。
在 if() 語句中使用樣式查詢比 @container 查詢有一個優勢——你可以根據元素上是否設定了自定義屬性來直接為該元素設定樣式,而無需檢查容器父元素上設定的樣式。
你還可以在樣式查詢中使用 and、or 或 not 邏輯。例如:
background-color: if(
style((--scheme: dark) or (--scheme: very-dark)): black;
);
background-color: if(
style((--scheme: dark) and (--contrast: hi)): black;
);
background-color: if(
not style(--scheme: light): black;
);
@container 查詢確實有一些優勢——使用 if() 樣式查詢一次只能設定單個屬性值,而 @container 查詢可以用於有條件地應用整套規則。這兩種方法是互補的,各有不同的用途。
請注意,容器樣式查詢目前不支援常規的 CSS 屬性,只支援 CSS 自定義屬性。例如,以下程式碼將無法工作:
if(
background-color: if(style(color: white): black;);
)
媒體查詢
一個媒體查詢 <if-test> 可以用來根據媒體查詢測試是否返回 true 來設定屬性的值。
你可以使用媒體型別。例如,下面的 <if-test> : <value> 對在列印媒體上返回 white,而 else 子句使得在非列印媒體上返回 #eeeeee。
background-color: if(
media(print): white;
else: #eeeeee;
)
你也可以使用媒體特性——如果當前視口寬度小於 700px,以下程式碼返回 0 auto;否則返回 20px auto。
margin: if(
media(width < 700px): 0 auto;
else: 20px auto;
)
當你需要根據媒體查詢結果改變單個屬性值時,這非常有用。
你還可以在媒體查詢中使用 and、or 或 not 邏輯。例如:
border-color: if(
media((width > 700px) and (width < 1000px)): blue;
);
border-color: if(
media((width < 500px) or (orientation: landscape)): blue;
);
background-color: if(
not media(width < 500px): blue;
else: red
);
當你想根據一個媒體查詢設定多個宣告或規則時,需要使用常規的 @media 結構。這兩種方法是互補的,各有不同的用途。
特性查詢
一個特性查詢 <if-test> 可以用來根據瀏覽器是否支援某個特定的屬性值來設定屬性的值。
例如,如果支援 lch() 顏色,以下程式碼將返回一個 lch() 顏色;否則返回一個 rgb() 顏色。
color: if(
supports(color: lch(75% 0 0)): lch(75% 0 0);
else: rgb(185 185 185);
)
選擇器支援查詢也同樣有效。如果瀏覽器支援 :buffering 偽類,以下程式碼將返回 1em;否則返回 initial。
margin-top: if(
supports(selector(:buffering)): 1em;
else: initial;
)
你還可以在特性查詢中使用 and、or 或 not 邏輯。例如:
margin-top: if(
supports((selector(:buffering)) and (color: blue)): 1em;
);
margin-top: if(
supports((selector(:buffering)) or (color: not-a-color)): 1em;
);
margin-top: if(
supports(not selector(:buffering)): 1em;
);
當你需要根據對某個特定值或獨立屬性的支援來改變單個屬性值時,在 if() 語句中使用特性查詢非常有用。當你想根據一個特性查詢設定多個宣告或規則時,常規的 @supports 結構更好。這兩種方法是互補的,各有不同的用途。
提供回退值
if() 語句不會優雅降級;需要為不支援的瀏覽器提供明確的回退值。
例如,在這種情況下,我們為不支援 if() 的瀏覽器提供了一個靜態的 padding 值。支援 if() 的瀏覽器會用第二個宣告覆蓋第一個宣告,根據 --size: "2xl" 自定義屬性是否設定來設定不同的內邊距值。
padding: 1em;
padding: if(style(--size: "2xl"): 1em; else: 0.25em);
備註: 記住要包含 else 條件。在支援 if() 的瀏覽器中,如果沒有包含 else 值且 --size 不等於 "2xl",padding 將被設定為 initial。
完整值和部分值
if() 函式可以作為任何 CSS 屬性的值,但它也可以用來決定屬性值的一部分。例如,下面的程式碼根據是否支援 lch() 顏色,在 border 簡寫屬性中設定了不同的 border-color。
border: if(
supports(color: lch(75% 0 0)): 3px solid lch(75% 0 0);
else: 3px solid silver;
);
然而,我們也可以只用 if() 函式來決定 border-color 元件。
border: 3px solid
if(
supports(color: lch(75% 0 0)): lch(75% 0 0); else: silver;
);
巢狀 if() 函式
因為 if() 函式可以替代整個屬性值或單個元件,所以可以在其他 if() 函式內部巢狀 if() 函式,也可以在 calc() 等其他函式內部巢狀。
例如,在這個宣告中,我們使用 if() 根據各種條件來設定 color 屬性值。我們有一個外部的 if() 函式,根據 --scheme 自定義屬性是否設定為 ice 或 fire 來返回一個特定的值(如果兩個條件都不滿足,則返回 else 值 black)。
然而,這兩個 <value> 本身也是 if() 函式。這些內部的 if() 函式會在使用者偏好深色配色方案時(透過 prefers-color-scheme 媒體查詢確定)返回一個淺色值,否則返回一個深色值。
color: if(
style(--scheme: ice):
if(
media(prefers-color-scheme: dark): #caf0f8;
else: #03045e;
);
style(--scheme: fire):
if(
media(prefers-color-scheme: dark): #ffc971;
else: #621708;
);
else: black
);
在下一個例子中,我們將 width 屬性設定為一個 calc() 函式,該函式從父元素寬度的百分比中減去 50px。這個百分比由一個 if() 函式表示,該函式測試 --scheme: wide 自定義屬性是否被設定。如果是,百分比為 70%,所以外部函式解析為 calc(70% - 50px)。如果不是,百分比為 50%,所以外部函式解析為 calc(50% - 50px)。
width: calc(if(
style(--scheme: wide): 70%;
else: 50%;
) - 50px);
正式語法
解析錯誤:意外的輸入示例
if() 的基本用法
在這個例子中,我們將展示三種 <if-test> 型別的基本用法。
HTML
我們的 HTML 中有一個 <section> 元素,裡面有兩個 <article> 元素,包含 <h2> 標題。這個 <section> 在其 style 屬性中設定了一個自定義屬性——--show-apple:true——我們稍後會用它來有條件地設定一個屬性值。
<section style="--show-apple:true">
<article><h2>First article</h2></article>
<article><h2>Second article</h2></article>
</section>
CSS
在我們的 CSS 中,我們首先選擇 <section> 元素,使用 flexbox 對其進行佈局,並設定兩個子 <article> 元素之間的 gap。然後,我們使用一個帶有 orientation 媒體查詢 <if-test> 的 if() 函式來設定 flex-direction 屬性的值,如果文件處於橫向方向,則為 row,如果處於縱向方向,則為 column。這使得 article 元素在寬屏上並排佈局,在窄屏上從上到下佈局。
section {
display: flex;
gap: 16px;
flex-direction: if(
media(orientation: landscape): row;
else: column;
)
}
接下來,我們選擇 <h2> 元素的 ::before 偽元素,將其 content 屬性設定為一個蘋果表情符號,但僅當 --show-apple: true 被設定時(我們之前在 HTML 中用內聯 <style> 實現了這一點)。我們透過一個帶有樣式查詢 <if-test> 的 if() 函式來實現這一點。
h2::before {
content: if(
style(--show-apple: true): "🍎 ";
);
}
最後,我們選擇 <h2> 元素本身。我們使用一個特性查詢 <if-test> 來測試瀏覽器是否支援 lch() 顏色,如果支援,則將 color 屬性設定為一個 lch() 顏色,否則設定為一個等效的十六進位制顏色。
h2 {
color: if(
supports(color: lch(29.57% 43.25 344.44)): lch(29.57% 43.25 344.44);
else: #792359;
)
}
結果
注意樣式是如何應用的。透過使用瀏覽器的開發者工具修改渲染的演示,來測試前兩個 if() 查詢的條件樣式。
- 移除
<section>元素的style屬性,注意蘋果表情符號是如何不再被渲染的。 - 將嵌入的
<iframe>的height屬性改為1200px。這將使方向從橫向變為縱向。注意佈局因此發生的變化。
用 if() 控制配色方案
這個演示展示瞭如何用 CSS if() 函式玩出真正的樂趣。其中,我們使用 if() 函式有條件地設定一些自定義屬性的值,從而使我們能夠控制整個配色方案!
HTML
我們的 HTML 包含一個 <article> 元素,裡面有一些內容——一個頂級標題、幾個 <p> 元素和一個 <aside>。我們還包含了一個 <form>,其中有一個 <select> 下拉選單,用於選擇配色方案。
<article>
<h1>Main heading</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipiscing elit.
Quisque faucibus ex sapien vitae pellentesque sem placerat.
In id cursus mi pretium tellus duis convallis.
</p>
<aside>
<h2>An aside</h2>
<p>
Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus
fringilla lacus nec metus bibendum egestas.
</p>
</aside>
<p>
Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut
hendrerit semper vel class aptent taciti sociosqu. Ad litora
torquent per conubia nostra inceptos himenaeos.
</p>
</article>
<form>
<label for="scheme">Choose color scheme:</label>
<select id="scheme">
<option value="">Default</option>
<option value="ice">Ice</option>
<option value="fire">Fire</option>
</select>
</form>
JavaScript
我們的 JavaScript 為 <select> 元素添加了一個 change 事件監聽器。當選擇了新值時,我們的指令碼會將 <article> 元素的 class 屬性設定為該值。
const articleElem = document.querySelector("article");
const selectElem = document.querySelector("select");
selectElem.addEventListener("change", () => {
articleElem.className = selectElem.value;
});
CSS
在我們的 CSS 中,我們給 <body> 元素設定了一個 700px 的 max-width,並使用 auto 的 margin 值使其居中。然而,我們使用一個帶有媒體查詢 <if-test> 的 if() 函式,在 margin 簡寫屬性中設定 margin-top 元件,如果視口寬度小於 700px,則為 0,如果更寬,則為 20px。這意味著在寬屏上,我們在內容頂部會有一點外邊距,但在窄屏上這會被移除,因為它看起來有點奇怪。
body {
max-width: 700px;
margin: if(
media(width < 700px): 0;
else: 20px;
) auto 0;
}
然後,我們將 --scheme 自定義屬性設定為與 <article> 元素的 class 名稱匹配。當在我們的 <select> 元素中選擇新值時,我們的 JavaScript 會設定該 class。你將在下一個 CSS 塊中看到該自定義元素值的重要性。
.ice {
--scheme: ice;
}
.fire {
--scheme: fire;
}
當我們將 CSS if() 函式與自定義屬性結合使用時,我們可以看到它們的真正威力。在這裡,我們使用 if() 函式,根據 --scheme 自定義屬性的值,將我們的 --color1 和 --color2 自定義屬性設定為不同的顏色值。然後,我們在 <article> 元素的 color、border 和 background-image 屬性,以及我們的 <aside> 元素的 color 和 background-color 屬性中使用 --color1 和 --color2 的值。
我們透過自定義屬性來控制整個配色方案,透過 if() 函式設定不同的值。
article {
padding: 20px;
--color1: if(
style(--scheme: ice): #03045e;
style(--scheme: fire): #621708;
else: black;
);
--color2: if(
style(--scheme: ice): #caf0f8;
style(--scheme: fire): #ffc971;
else: white;
);
color: var(--color1);
border: 3px solid var(--color1);
background-image: linear-gradient(
to left,
var(--color2),
white,
var(--color2)
);
}
aside {
color: var(--color2);
background-color: var(--color1);
padding: 20px;
}
最後,我們在另外幾個地方使用了 if() 函式。
- 如果視口寬度大於
700px,我們將<h1>元素的font-size設定為calc(3rem + 2vw),否則設定為3rem。這意味著在寬屏上,字型大小會隨著視口寬度的變化而動態更新,但在窄屏上保持不變。 - 我們根據
--scheme自定義屬性的值,為<h1>元素的::before偽類的content設定了一個合適的表情符號。
h1 {
margin: 0;
font-size: if(
media(width > 700px): calc(3rem + 2vw);
else: 3rem;
);
}
h1::before {
content: if(
style(--scheme: ice): "❄️ ";
style(--scheme: fire): "🔥 ";
else: "";
);
}
結果
此演示渲染如下:
嘗試選擇不同的配色方案值,看看對外觀和感覺的影響。
規範
| 規範 |
|---|
| CSS 值和單位模組 Level 5 # if-notation |
瀏覽器相容性
載入中…