calc-size()

可用性有限

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

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

calc-size() CSS 函式允許您對 固有尺寸 值執行計算,例如 autofit-contentmax-content;這不被常規的 calc() 函式支援。

calc-size() 的返回值也可以插值,從而使尺寸關鍵字值能夠用於動畫過渡。實際上,在屬性值中包含 calc-size() 會自動將 interpolate-size: allow-keywords 應用於選擇。

但是請注意,interpolate-size 是繼承的,因此將其應用於一個元素會為應用於該元素及其子元素的每個屬性啟用固有尺寸關鍵字的插值。因此,interpolate-size 是啟用固有尺寸動畫的首選解決方案。您只應在需要計算時才使用 calc-size() 來啟用固有尺寸動畫。

語法

css
/* Pass a value through calc-size() */
calc-size(auto, size)
calc-size(fit-content, size)

/* Perform a calculation */
calc-size(min-content, size + 100px)
calc-size(fit-content, size / 2)

/* Calculation including a function */
calc-size(auto, round(up, size, 50px))

引數

calc-size() 函式的語法如下:

calc-size(<calc-size-basis>, <calc-sum>)

引數為:

<calc-size-basis>

您希望在其上執行計算的值(最常見的是固有尺寸)。

<calc-sum>

定義要對 <calc-size-basis> 執行的計算的表示式。

返回值

返回一個值,該值等於透過 <calc-sum> 表示式修改的 <calc-size-basis>。由於 <calc-size-basis> 值是固有尺寸值,因此返回值是修改後的固有尺寸值,其行為類似於輸入到函式中的固有尺寸值。

描述

某些瀏覽器佈局演算法對固有尺寸關鍵字有特殊行為。calc-size() 函式明確定義為表示固有尺寸而不是 <length-percentage>,從而強制執行正確性。calc-size() 允許以安全、明確的方式對固有尺寸值執行計算。

第一個引數 (<calc-size-basis>) 的有效值

第一個 calc-size() 引數可以是以下固有值之一:

此引數還可以採用一些特殊值:

  • 巢狀的 calc-size() 值。這並不是您會經常做的事情,但它確保了使用 CSS 變數 作為 <calc-size-basis> 總是有效的,前提是該變數是 calc-size() 所設定屬性的有效值。例如,這將有效:

    css
    section {
      height: calc-size(calc-size(max-content, size), size + 2rem);
    }
    

    以及這個:

    css
    :root {
      --intrinsic-size: calc-size(max-content, size);
    }
    
    section {
      height: calc-size(var(--intrinsic-size), size + 2rem);
    }
    
  • 另一個 <calc-sum>,其限制與為第二個引數指定的 <calc-sum> 相同,只是不能包含 size 關鍵字。您可能不會這樣做,因為您不再對固有尺寸值進行計算,但如果自定義屬性值是 <calc-sum>,該函式仍然會有效。例如,這將直接有效,或者如果您使用值為 300px + 2rem 的自定義屬性:

    css
    section {
      height: calc-size(300px + 2rem, size / 2);
    }
    
  • 關鍵字 any,表示未指定的確定尺寸。在這種情況下,第二個引數中不能包含 size 關鍵字,calc-size() 返回第二個引數計算的結果。例如:

    css
    section {
      height: calc-size(any, 300px * 1.5); /* Returns 450px */
    }
    

在同一個計算中混合不同的固有尺寸不起作用。例如,max-content - min-content 沒有意義。calc-size() 在每個計算中只允許一個固有尺寸值,從而避免了這個問題。

第二個引數 (<calc-sum>) 的有效值

第二個 calc-size() 引數是 <calc-sum> 表示式。

在此表示式中:

  • 關鍵字 size 表示作為第一個引數指定的 <calc-size-basis>
  • 運算元可以包括 size,以及在上下文中任何有意義的值型別。
  • 可以包含 +-*/ 運算子。
  • 可以包含其他數學函式,例如 round()max(),甚至是巢狀的 calc-size()
  • 整個表示式必須匹配 <length-percentage>,並解析為 <length>

啟用固有尺寸值的動畫

calc-size() 返回值可以插值,從而可以在 <length-percentage> 值和 calc-size() 固有尺寸返回值之間進行動畫。

注意:如果可能,您應避免動畫盒模型屬性,以減少佈局事件並減輕由此對效能造成的影響(請參閱關鍵渲染路徑 > 佈局)。

例如,您可以使用過渡來動畫容器的 width0auto 之間,如下所示:

css
section {
  width: 0;
  transition: width ease 1s;
}

section:hover,
section:focus {
  width: calc-size(auto, size);
}

在上述情況下,我們沒有計算任何東西——我們將 auto 放入 calc-size() 並將其不變地返回。interpolate-size 屬性使得像上述那樣的動畫在大多數情況下更容易實現,尤其是在有多個動畫需要考慮時。它是繼承的,因此只需在祖先屬性上宣告一次,這意味著我們可以不使用 calc-size() 就能在 0auto 之間進行過渡。

只有在固有尺寸動畫還需要計算時,才應使用 calc-size() 函式。例如,在以下情況下,我們正在動畫 width 對固有尺寸最終狀態應用計算:

css
section {
  width: 0;
  transition: width ease 1s;
}

section:hover,
section:focus {
  width: calc-size(auto, size + 2rem);
}

calc-size() 有用的一個情況是,當您想要在固有尺寸和同一固有尺寸的修改版本之間進行動畫時。這在使用 interpolate-sizecalc() 時是不可能的。例如,以下 @keyframes 定義動畫容器的 widthfit-contentfit-content 的 70% 之間(使用 calc-size() 計算)。

css
@keyframes narrower {
  from {
    width: fit-content;
  }

  to {
    width: calc-size(fit-content, size * 0.7);
  }
}

注意:請注意,calc-size() 不支援在兩個不同的固有尺寸值之間進行動畫。

正式語法

<calc-size()> = 
calc-size( <calc-size-basis> , <calc-sum> )

<calc-size-basis> =
<size-keyword> |
<calc-size()> |
any |
<calc-sum>

<calc-sum> =
<calc-product> [ [ '+' | '-' ] <calc-product> ]*

<calc-product> =
<calc-value> [ [ '*' | / ] <calc-value> ]*

<calc-value> =
<number> |
<dimension> |
<percentage> |
<calc-keyword> |
( <calc-sum> )

<calc-keyword> =
e |
pi |
infinity |
-infinity |
NaN

示例

calc-size 的基本用法

此示例演示了使用 calc-size() 對容器進行基本尺寸調整

HTML

HTML 包含一個 <section> 元素,其中包含一些子內容。

html
<section>
  <h2>Favorite quote</h2>

  <p>
    Fashion is something so ugly it has to be changed every fifteen minutes.
  </p>
</section>

CSS

在 CSS 中,我們使用 Flexbox 將子元素在 <section> 內部居中,並將 <section>widthheight 設定為 calc-size() 函式。width 設定為 fit-content6remheight 設定為 auto 乘以二。

css
section {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;

  width: calc-size(fit-content, size + 6rem);
  height: calc-size(auto, size * 2);
}

為了簡潔起見,其餘的 CSS 已隱藏。

結果

我們為文字建立了一些水平和垂直空間,使其居中,而無需使用內邊距。

基本 calc-size 動畫

此示例演示如何使用 calc-size() 在特定尺寸和固有尺寸之間進行動畫。該演示展示了一個角色徽章/“名牌”,可以懸停或聚焦以顯示有關角色的資訊。顯示透過在設定長度和 max-content 之間的 height 過渡來處理。

HTML

HTML 包含一個 <section> 元素,其上設定了 tabindex="0",以便它可以接收鍵盤焦點。<section> 包含 <header><main> 元素,每個元素都有自己的子內容。

html
<section tabindex="0">
  <header>
    <h2>Chris Mills</h2>
  </header>
  <main>
    <p>Chris is the silent phantom of MDN.</p>
    <ul>
      <li><strong>Height</strong>: 3.03m</li>
      <li><strong>Weight</strong>: 160kg</li>
      <li><strong>Tech Fu</strong>: 7</li>
      <li><strong>Bad Jokes</strong>: 9</li>
    </ul>
  </main>
</section>

CSS

在 CSS 中,我們將 <section>height 設定為 2.5rem,將 overflow 設定為 hidden,以便預設只顯示 <header>,然後指定一個 transition,在狀態更改期間在 1 秒內動畫 <section>height。最後,我們將 <section>height 設定為 :hover:focus 上的 calc-size() 函式呼叫。函式返回值等同於 max-content + 2rem

css
section {
  height: 2.5rem;
  overflow: hidden;
  transition: height ease 1s;
}

section:hover,
section:focus {
  height: calc-size(max-content, size + 2rem);
}

為了簡潔起見,其餘的 CSS 已隱藏。

結果

嘗試將滑鼠懸停在 <section> 上或透過鍵盤聚焦它 — 它將動畫到其完整高度 + 2rem,顯示所有內容並在底部留出 2rems 的額外空間。

根據 fit-content 調整閱讀寬度

此示例展示了一個包含文字的容器和一個按鈕,可以單擊該按鈕根據閱讀偏好使容器寬度變窄或變寬。

HTML

HTML 包含一個 <section> 元素,其中包含子文字內容,以及一個 <button> 用於更改 <section> 的寬度。

html
<section class="easy-reader">
  <h2>Easy reader</h2>

  <p>
    Eius velit aperiam ipsa. Deleniti eum excepturi ut magni maxime maxime
    beatae. Dicta aperiam est laudantium ut illum facere qui officiis. Sunt
    deleniti quam id. Quis sunt voluptatem praesentium minima dolorum autem
    consequatur velit.
  </p>

  <p>
    Vitae ab incidunt velit aspernatur deleniti distinctio rerum. Et natus sed
    et quos mollitia quia quod. Quae officia ex ea. Ducimus ut voluptatem et et
    debitis. Quidem provident laboriosam exercitationem similique deleniti.
    Temporibus vel veniam mollitia magni unde a nostrum.
  </p>

  <button class="width-adjust">Narrower</button>
</section>

CSS

在 CSS 中,我們將 <section>width 預設設定為 fit-content。然後我們定義兩組 @keyframesnarrower,它從 fit-content 動畫到 fit-content 的 70%(使用 calc-size() 計算),以及 wider,它動畫相同的值但方向相反。最後,我們將這些動畫附加到兩個類——.narrower.wider。每個動畫都定義為持續一秒,並在完成後保持最終狀態。

css
section {
  width: fit-content;
}

@keyframes narrower {
  from {
    width: fit-content;
  }

  to {
    width: calc-size(fit-content, size * 0.7);
  }
}

@keyframes wider {
  from {
    width: calc-size(fit-content, size * 0.7);
  }

  to {
    width: fit-content;
  }
}

.narrower {
  animation: narrower 1s ease forwards;
}

.wider {
  animation: wider 1s ease forwards;
}

為了簡潔起見,其餘的 CSS 已隱藏。

JavaScript

JavaScript 提供了一個更窄/更寬的切換功能,當按鈕被點選時,它會將相關類應用於 <section>

js
const widthAdjustBtn = document.querySelector(".width-adjust");
const easyReader = document.querySelector(".easy-reader");

widthAdjustBtn.addEventListener("click", () => {
  if (easyReader.classList.length === 1) {
    easyReader.classList.add("narrower");
    widthAdjustBtn.textContent = "Wider";
  } else if (easyReader.classList.contains("wider")) {
    easyReader.classList.replace("wider", "narrower");
    widthAdjustBtn.textContent = "Wider";
  } else if (easyReader.classList.contains("narrower")) {
    easyReader.classList.replace("narrower", "wider");
    widthAdjustBtn.textContent = "Narrower";
  }
});

結果

嘗試點選 <button> 幾次,以在寬和窄閱讀寬度之間調整 <section>,這是透過根據 fit-content 值操作 width 來實現的。

calc-size() 函式內部使用函式

如前所述,可以在 calc-size() 內部使用另一個函式。此示例將 field-sizing: content 設定在 <input> 元素上,使其寬度與輸入內容相同,然後使用 calc-size() 內部的 max() 函式來確保 <input> 至少有一個最小尺寸,並且只有當輸入文字寬度超過該尺寸時才開始增長——透過將其設定為 fit-content20px

HTML

HTML 包含一個 <form> 元素,其中包含三個文字 <input> 型別。每個 <input> 都帶有一個相關的 <label> 以使表單可訪問,並應用了 maxlength 以防止輸入值過長導致表單佈局混亂。

html
<form>
  <div>
    <label for="name">Name:</label>
    <input type="text" id="name" name="name" maxlength="48" />
  </div>
  <div>
    <label for="email">Email:</label>
    <input type="email" id="email" name="email" maxlength="48" />
  </div>
  <div>
    <label for="address">Address:</label>
    <input type="text" id="address" name="address" maxlength="60" />
  </div>
</form>

CSS

在 CSS 中,我們將 <label> 元素的 width 設定為 100px。我們將 field-sizing: content 設定在 <input> 元素上,使其寬度與輸入內容相同——預設情況下,如果未輸入任何值,它們將沒有寬度。為了解決這個問題,我們將它們的 width 值設定為 calc-size(fit-content, max(100px, size + 20px))。這意味著即使沒有輸入任何值,它們也至少有 100px 寬。當輸入值寬度超過 100px 時,它們的 width 會變為 fit-content20px,這意味著它們會隨著內容大小增長,但在右側保留 20px 的間隙。

css
label {
  width: 100px;
}

input {
  field-sizing: content;
  width: calc-size(fit-content, max(100px, size + 20px));
}

為了簡潔起見,其餘的 CSS 已隱藏。

結果

嘗試在表單輸入框中輸入一些文字,看看當輸入值開始達到 max() 函式強制的最小寬度時,它們是如何增長的。

規範

規範
CSS 值和單位模組 Level 5
# calc-size

瀏覽器相容性

另見