if()

可用性有限

此特性不是基線特性,因為它在一些最廣泛使用的瀏覽器中不起作用。

實驗性: 這是一項實驗性技術
在生產中使用此技術之前,請仔細檢查瀏覽器相容性表格

if() CSS 函式允許根據條件測試的結果為屬性設定不同的值。該測試可以基於樣式查詢媒體查詢特性查詢

語法

css
/* 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>;
<if-condition>

一個 <if-test>else 關鍵字。

<if-test>

一個樣式查詢媒體查詢特性查詢

else

一個關鍵字,代表一個總是評估為 true 的 <if-condition>

<value>

一個屬性值。

返回值

一個值或保證無效值

描述

CSS if() 函式為 CSS 屬性值提供了條件邏輯,其工作方式類似於 JavaScript 的 if...else 語句。

if() 函式可以在任何屬性的值中使用,並且可以包含零個或多個以分號分隔的 <if-condition>。每個 <if-condition> 要麼是一個 <if-test> : <value> 對,要麼是一個 else : <value> 對。最後一個 <if-condition> 後面的分號是可選的。

返回值按如下方式計算

  1. <if-condition> 表示式按照它們在函式中出現的順序進行評估。
  2. 第一個評估為 true<if-condition> 將返回其關聯的 <value>
  3. 如果沒有 <if-condition> 評估為 true,則函式返回一個 <guaranteed-invalid>。如果在具有回退值的值語句中使用 if() 函式(例如自定義屬性anchor() 函式),這會表現為無效或 false

例如

css
div {
  background-image: if(
    style(--scheme: ice): linear-gradient(#caf0f8, white, #caf0f8);
    style(--scheme: fire): linear-gradient(#ffc971, white, #ffc971);
    else: none;
  );
}

在這個例子中,我們根據 --scheme 自定義屬性是否設定為 icefire,為 <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> 對永遠不會被評估。

css
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> 對同樣永遠不會被評估。

css
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> 對,或者什麼都不包含,它仍然是有效的。以下屬性值都是有效的。

css
background-color: if(else: yellow);
background-image: if();

這些函式並沒有什麼用。包含它們是為了證明其有效性。在這種情況下,background-color 值將始終設定為 yellow,而 background-image 將被設定為其初始值。你最好直接將 background-color 設定為 yellow,將 background-image 設定為 initialnone

if-test 的型別

<if-test> 接受三種查詢型別之一。本節將詳細介紹每一種。

樣式查詢

一個樣式查詢 <if-test> 允許你測試某個元素上是否設定了特定的屬性值,並因此為另一個屬性應用一個值。我們之前已經看過幾個樣式查詢的例子;讓我們再看一個例子。

css
background-image: if(
  style(--scheme: ice): linear-gradient(#caf0f8, white, #caf0f8);
  else: none;
);

如果在同一個元素上 --scheme 自定義屬性被設定為 ice,則返回提供的 linear-gradient() 值。如果不是,則返回 none

if() 語句中使用樣式查詢比 @container 查詢有一個優勢——你可以根據元素上是否設定了自定義屬性來直接為該元素設定樣式,而無需檢查容器父元素上設定的樣式。

你還可以在樣式查詢中使用 andornot 邏輯。例如:

css
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 自定義屬性。例如,以下程式碼將無法工作:

css
if(
  background-color: if(style(color: white): black;);
)

媒體查詢

一個媒體查詢 <if-test> 可以用來根據媒體查詢測試是否返回 true 來設定屬性的值。

你可以使用媒體型別。例如,下面的 <if-test> : <value> 對在列印媒體上返回 white,而 else 子句使得在非列印媒體上返回 #eeeeee

css
background-color: if(
  media(print): white;
  else: #eeeeee;
)

你也可以使用媒體特性——如果當前視口寬度小於 700px,以下程式碼返回 0 auto;否則返回 20px auto

css
margin: if(
  media(width < 700px): 0 auto;
  else: 20px auto;
)

當你需要根據媒體查詢結果改變單個屬性值時,這非常有用。

你還可以在媒體查詢中使用 andornot 邏輯。例如:

css
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() 顏色。

css
color: if(
  supports(color: lch(75% 0 0)): lch(75% 0 0);
  else: rgb(185 185 185);
)

選擇器支援查詢也同樣有效。如果瀏覽器支援 :buffering 偽類,以下程式碼將返回 1em;否則返回 initial

css
margin-top: if(
  supports(selector(:buffering)): 1em;
  else: initial;
)

你還可以在特性查詢中使用 andornot 邏輯。例如:

css
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" 自定義屬性是否設定來設定不同的內邊距值。

css
padding: 1em;
padding: if(style(--size: "2xl"): 1em; else: 0.25em);

備註: 記住要包含 else 條件。在支援 if() 的瀏覽器中,如果沒有包含 else 值且 --size 不等於 "2xl",padding 將被設定為 initial

完整值和部分值

if() 函式可以作為任何 CSS 屬性的值,但它也可以用來決定屬性值的一部分。例如,下面的程式碼根據是否支援 lch() 顏色,在 border 簡寫屬性中設定了不同的 border-color

css
border: if(
  supports(color: lch(75% 0 0)): 3px solid lch(75% 0 0);
  else: 3px solid silver;
);

然而,我們也可以只用 if() 函式來決定 border-color 元件。

css
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 自定義屬性是否設定為 icefire 來返回一個特定的值(如果兩個條件都不滿足,則返回 elseblack)。

然而,這兩個 <value> 本身也是 if() 函式。這些內部的 if() 函式會在使用者偏好深色配色方案時(透過 prefers-color-scheme 媒體查詢確定)返回一個淺色值,否則返回一個深色值。

css
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)

css
width: calc(if(
    style(--scheme: wide): 70%;
    else: 50%;
  ) - 50px);

正式語法

解析錯誤:意外的輸入

示例

if() 的基本用法

在這個例子中,我們將展示三種 <if-test> 型別的基本用法。

HTML

我們的 HTML 中有一個 <section> 元素,裡面有兩個 <article> 元素,包含 <h2> 標題。這個 <section> 在其 style 屬性中設定了一個自定義屬性——--show-apple:true——我們稍後會用它來有條件地設定一個屬性值。

html
<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 元素在寬屏上並排佈局,在窄屏上從上到下佈局。

css
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() 函式來實現這一點。

css
h2::before {
  content: if(
    style(--show-apple: true): "🍎 ";
  );
}

最後,我們選擇 <h2> 元素本身。我們使用一個特性查詢 <if-test> 來測試瀏覽器是否支援 lch() 顏色,如果支援,則將 color 屬性設定為一個 lch() 顏色,否則設定為一個等效的十六進位制顏色。

css
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> 下拉選單,用於選擇配色方案。

html
<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 屬性設定為該值。

js
const articleElem = document.querySelector("article");
const selectElem = document.querySelector("select");

selectElem.addEventListener("change", () => {
  articleElem.className = selectElem.value;
});

CSS

在我們的 CSS 中,我們給 <body> 元素設定了一個 700pxmax-width,並使用 automargin 值使其居中。然而,我們使用一個帶有媒體查詢 <if-test>if() 函式,在 margin 簡寫屬性中設定 margin-top 元件,如果視口寬度小於 700px,則為 0,如果更寬,則為 20px。這意味著在寬屏上,我們在內容頂部會有一點外邊距,但在窄屏上這會被移除,因為它看起來有點奇怪。

css
body {
  max-width: 700px;
  margin: if(
    media(width < 700px): 0;
    else: 20px;
  ) auto 0;
}

然後,我們將 --scheme 自定義屬性設定為與 <article> 元素的 class 名稱匹配。當在我們的 <select> 元素中選擇新值時,我們的 JavaScript 會設定該 class。你將在下一個 CSS 塊中看到該自定義元素值的重要性。

css
.ice {
  --scheme: ice;
}

.fire {
  --scheme: fire;
}

當我們將 CSS if() 函式與自定義屬性結合使用時,我們可以看到它們的真正威力。在這裡,我們使用 if() 函式,根據 --scheme 自定義屬性的值,將我們的 --color1--color2 自定義屬性設定為不同的顏色值。然後,我們在 <article> 元素的 colorborderbackground-image 屬性,以及我們的 <aside> 元素的 colorbackground-color 屬性中使用 --color1--color2 的值。

我們透過自定義屬性來控制整個配色方案,透過 if() 函式設定不同的值。

css
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 設定了一個合適的表情符號。
css
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

瀏覽器相容性

另見