progress()

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

progress() CSS 函式返回一個 <number> 值,表示一個值(進度值)相對於另外兩個值(進度起始值和結束值)的位置。

語法

css
/* With fixed progress value */
progress(300, 0, 1000)
progress(50px, 0px, 100px)
progress(50%, 30%, 80%)

/* With custom property */
progress(var(--container-width), 320, 1200)

/* Inside math function */
calc((progress(var(--container-width), 20%, 80%) / 2) + 0.5)

/* Inside non-math function */
rgb(
  calc(255 * progress(var(--container-width), 320px, 1200px))
  calc(255 * progress(var(--container-width), 320px, 1200px)) 255 / 0.5
);

/* Math function inside progress() */
progress(calc(20 + 30), 0, 100)

引數

progress() 函式接受三個以逗號分隔的 <calc-sum> 表示式作為引數。

progress(<calc-sum>, <calc-sum>, <calc-sum>)

它們分別是:

進度

需要計算其相對於另外兩個值的位置的值。

進度起始值

進度的下限。

進度結束值

進度的上限。

返回值

一個 <number>,表示進度值相對於另外兩個值的位置。計算方式如下:

(progress - progress start) / (progress end - progress start)

如果進度值介於進度起始值和進度結束值之間,返回值將在 01 之間,表示一個百分比。如果進度值小於進度起始值或大於進度結束值,函式仍然有效,但返回值將被分別限制在 01

描述

CSS progress() 函式提供了一種計算進度比率的方法,這對於建立進度條動畫或隨著寬度增加而淡入以顯示其內容的盒子等用例非常有用。

最簡單的用法可能如下:

css
opacity: progress(5, 0, 10);

在這種情況下,opacity 的計算值為 0.5,因為 5 是 010 的中間值。

允許的單位型別

progress() 函式的引數可以是數學表示式或簡單值。這些值(或表示式結果)可以是任何 <number><dimension><percentage> 值。它們可以有不同的單位,但必須都是同一型別,否則函式無效。

我們之前看到的例子是有效的——它的所有引數都是無單位的 <number> 值:

css
progress(5, 0, 10)

下一個例子也是有效的——它的所有引數都有 <length> 單位。在後臺,計算值被用於計算。如果在計算時 font-size16px,那麼 3em 將解析為 48px,這是 0px100px 之間距離的 48%,所以返回值將是 0.48

css
progress(3em, 0px, 100px)

然而,本節中最後幾個例子是無效的。型別不匹配,因此最終的計算沒有意義。

css
progress(3s, 0px, 100px)
progress(3em, 0, 100)

建立無單位值

progress() 函式輸出無單位值,因此可以像 tan(atan2()) 技巧一樣,用於從值中移除單位。但請注意,由於 CSS 型別化算術 行為的更新,這也可以透過簡單的除法來實現。

progress() 與其他函式和自定義屬性結合使用

因為 progress() 總是返回一個介於 01 之間的無單位值,所以通常會將其與另一個數學函式(如 calc())結合使用,以輸出你想要的值和單位。你還可以在 progress() 函式中使用 CSS 自定義屬性——這是很合理的,因為你通常希望在多個地方設定相同的值,和/或將它們基於透過 JavaScript 設定的自定義屬性。

以下示例計算視口寬度在 320px 的最小寬度和 1200px 的最大寬度之間的百分比。calc() 函式用於將 progress() 的返回值乘以 600px,將其轉換為一個畫素值,該值將是視口寬度在 320px1200px 之間進度值的一半。

css
width: calc(progress(100vw, 320px, 1200px) * 600px);

例如,如果視口寬度為 700px,進度值將計算為 ((700 - 320) / (1200 - 320)) = 0.431818。然後寬度將計算為 0.431818 * 600px,等於 259.1px

下一個示例是前一個的更新,其中我們為進度、進度起始和進度結束值使用了自定義屬性。

css
width: calc(
  progress(
      var(--container-width),
      var(--custom-min-width),
      var(--custom-max-width)
    ) *
    var(--custom-max-width)
);

只要你的函式為這些值返回有效的型別,就可以使用 progress() 函式來計算其他函式內的單個值以及簡寫屬性值中的元件值。

這可能會導致一些複雜的表示式。例如,在這裡我們計算一個 rgb() 顏色的前兩個通道,使其與之前的寬度比例成正比:

css
background-color: rgb(
  calc(
      255 *
        progress(
          var(--container-width),
          var(--custom-min-width),
          var(--custom-max-width)
        )
    )
    calc(
      255 *
        progress(
          var(--container-width),
          var(--custom-min-width),
          var(--custom-max-width)
        )
    )
    255 / 0.5
);

正式語法

<progress()> = 
progress( <calc-sum> , <calc-sum> , <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

示例

progress() 的基本用法

在這個例子中,我們將展示 progress() 函式的基本用法,將進度條的 width 設定為一個百分比,該百分比等於其父元素的 width 在其 min-widthmax-width 之間的進度比率。

HTML

我們的 HTML 有一個代表我們內容的 <section> 元素,以及一個代表寬度進度條的 <div> 元素。

html
<section>
  <div class="progress"></div>
</section>

CSS

在我們的 CSS 中,我們首先在 <section> 元素上設定一些自定義屬性來表示其 min-widthmax-widthwidth。然後我們將這些屬性設定為相應的自定義屬性值,再給我們的 <section> 一個純色的 background-color,使其可見。

css
section {
  --custom-min-width: 300px;
  --custom-max-width: 700px;
  --custom-width: 600px;

  min-width: var(--custom-min-width);
  max-width: var(--custom-max-width);
  width: var(--custom-width);

  background-color: cyan;
}

現在來看我們的 <div>——我們首先給它一個 height 和一個深色的 background-color,使其在我們的 <section> 元素上突出顯示。然後,我們透過使用 progress() 函式計算寬度在最小和最大寬度之間的進度比率來計算其 width,再使用 calc() 函式將 progress() 的返回值乘以 100%,以返回一個百分比。

css
.progress {
  height: 4px;
  background-color: red;

  width: calc(
    progress(
        var(--custom-width),
        var(--custom-min-width),
        var(--custom-max-width)
      ) *
      100%
  );
}

結果

此演示將呈現如下:

<div> 的寬度是 <section> 寬度的 75%,因為 min-width400pxmax-width700px,而 width600px,這是前兩個值之間距離的 75%

容器上的調整大小效果

這個例子展示了一些更復雜的 progress() 函式用法,當瀏覽器視窗調整大小時會產生一些有趣的效果。

此示例在桌面瀏覽器選項卡中以全尺寸渲染時效果更好。因此,我們沒有在此頁面中嵌入即時示例。你可以在 CSS progress() 函式演示中找到它的即時執行(另請參閱原始碼)。

在單獨的選項卡中開啟即時示例,並嘗試增加和減少瀏覽器視窗的寬度以檢視效果。請保持此頁面開啟,以便在閱讀下面的解釋時可以參考。

HTML

我們的 HTML 有一個包含其餘內容的 <article> 元素,以及兩個 <section> 元素——一個用於懸掛背景圖片,另一個用於包含我們的內容。<section class="content"> 還包含一個 <div class="progress">,表示一個寬度進度條,與我們之前的演示中的那個相同。為簡潔起見,我們省略了其餘內容。

html
<article>
  <section class="background"></section>
  <section class="content">
    <div class="progress"></div>
    <!-- Content here -->
  </section>
</article>

JavaScript

在我們的指令碼中,我們首先獲取對 <article> 元素的引用。然後我們定義一個名為 setContainerWidth() 的函式,該函式透過 Element.getBoundingClientRect() 獲取 <article> 的客戶端寬度,並在其上設定一個名為 --container-width 的自定義屬性,該屬性等於客戶端寬度向下取整後附加 px 的值。

然後我們在 Window 物件上設定一個 resize 事件監聽器,當瀏覽器視窗調整大小時執行 setContainerWidth()。我們還在頁面載入時執行它一次,以在 <article> 元素上設定 --container-width 自定義屬性。

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

function setContainerWidth() {
  const clientWidth = articleElem.getBoundingClientRect().width;
  articleElem.style.setProperty(
    "--container-width",
    `${Math.floor(clientWidth)}px`,
  );
}

window.addEventListener("resize", setContainerWidth);

setContainerWidth();

設定好之後,我們現在可以根據 --container-width 設定一些屬性值,這樣我們的設計部分就會隨著視窗調整大小而動態變化。

CSS

以下部分僅解釋與我們在演示中使用 progress() 函式相關的 CSS。有關完整的 CSS,請參閱 CSS 原始碼

我們首先使用 flexbox<article><body> 內居中,然後在其上設定一些自定義屬性來表示我們將在其他地方使用的 min-widthmax-width 值。然後我們針對 <article> 元素,給它 min-widthmax-width 值,等於我們之前設定的自定義屬性。我們將其 position 設定為 relative,以便我們可以相對於它定位其內容,然後給它一個百分比的 width、固定的 heightborder

css
body {
  height: inherit;
  display: flex;
  justify-content: center;
  align-items: center;
  --custom-min-width: 320px;
  --custom-max-width: 1200px;
}

article {
  min-width: var(--custom-min-width);
  max-width: var(--custom-max-width);
  position: relative;
  width: 70%;
  height: 600px;
  border: 3px solid black;
}

現在來看我們的 progress <div>。我們將其 width 設定為等於一個百分比,該百分比基於透過 JavaScript 在 <article> 元素上設定的 --container-width 自定義屬性在其 min-widthmax-width 之間的進度比率(我們在這裡為第二個和第三個 progress() 引數使用與 <article>min-widthmax-width 相同的自定義屬性)。

我們還給它一個 heightbackground-color,然後將其絕對定位在 <article> 的左上角。

css
.progress {
  width: calc(
    progress(
        var(--container-width),
        var(--custom-min-width),
        var(--custom-max-width)
      ) *
      100%
  );
  height: 4px;
  background-color: red;
  position: absolute;
  top: 0;
  left: 0;
}

接下來,我們來看我們的 background <section>。我們將其相對於 <article> 絕對定位,在其上設定 inset: 0,使其採用相同的大小並覆蓋在其上方。然後我們在其上設定一個相當寬的 background-image,並透過給 background-position-x 屬性與進度條的 width 屬性相同的值來定位背景圖片。這樣做的效果是,當你增加瀏覽器視窗的寬度時,背景圖片會向左移動,從而產生一個很好的圖片滾動效果。

css
.background {
  position: absolute;
  inset: 0;
  background-image: url("https://mdn.github.io/shared-assets/images/examples/wide-background.jpg");
  background-position-x: calc(
    progress(
        var(--container-width),
        var(--custom-min-width),
        var(--custom-max-width)
      ) *
      100%
  );
}

我們將 content <section> 絕對定位,使其覆蓋在 background <section> 之上,然後給它一些 padding。然後,我們使用與之前相同的進度比率,在瀏覽器視窗調整大小時改變兩個屬性值:

  • 我們改變 background-color 的 R 和 G 分量,在每種情況下都將進度比率乘以 255,以獲得成比例的通道值。隨著視窗變寬,背景顏色變得不那麼藍而更白,使場景看起來像是從黑夜到白天(顏色值的不透明度為 0.5,因此它起到為底層影像著色的作用)。
  • 我們改變 opacity,以便當視窗變寬時,內容會稍微淡入。
css
.content {
  position: absolute;
  inset: 0;
  padding: 20px;
  background-color: rgb(
    calc(
        255 *
          progress(
            var(--container-width),
            var(--custom-min-width),
            var(--custom-max-width)
          )
      )
      calc(
        255 *
          progress(
            var(--container-width),
            var(--custom-min-width),
            var(--custom-max-width)
          )
      )
      255 / 0.5
  );
  opacity: calc(
    (
        progress(
            var(--container-width),
            var(--custom-min-width),
            var(--custom-max-width)
          ) /
          2
      ) +
      0.5
  );
}

規範

規範
CSS 值和單位模組 Level 5
# progress

瀏覽器相容性

另見