以高度為高度:自動;(以及其他內建大小關鍵字) 在 CSS 中

使用 interpolate-size 屬性或 calc-size() 函式,即可在長度和內在大小關鍵字之間順暢轉換,並加上動畫效果。

發布日期:2024 年 9 月 17 日

簡介

CSS 常見要求功能是能夠以動畫效果顯示 height: auto。這項要求的微小變化是轉換 width 屬性,而非 height,或是轉換至 min-contentmax-contentfit-content 等關鍵字所代表的任何其他內在大小

舉例來說,在下列示範中,如果標籤在游標懸停在圖示上時,能以流暢的動畫效果調整至自然寬度,那就太棒了。

使用的 CSS 如下:

nav a {
    width: 80px;
    overflow-x: clip;
    transition: width 0.35s ease; /* 👈 Transition the width */

    &:hover,
    &:focus-visible {
        width: max-content; /* 👈 Doesn't work with transitions */
    }
}

雖然已宣告 transition 來轉換 width 屬性,且 width: auto 已在 :hover 宣告,並不會順利轉換。而是突然改變。

使用 interpolate-size 設定動畫,在內在大小關鍵字之間轉換

瀏覽器支援

  • Chrome:129。
  • Edge:不支援。
  • Firefox:不支援。
  • Safari:不支援。

資料來源

您可以透過 CSS interpolate-size 屬性控制是否允許使用 CSS 內在大小設定關鍵字的動畫和轉場效果。

預設值為 numeric-only,不會啟用插補。將屬性設為 allow-keywords 時,如果瀏覽器可以為這些關鍵字製作動畫,您可以選擇從長度到 CSS 內在大小關鍵字的插補。

根據規格

  • numeric-only:無法對 <intrinsic-size-keyword> 進行插補。
  • allow-keywords:如果其中一個值是 <intrinsic-size-keyword>,另一個值是 <length-percentage>,則可以插補兩個值。[…]

由於 interpolate-size 屬性是繼承而來的屬性,因此您可以在 :root 上宣告此屬性,以便在整份文件中關於內建或從內用大小調整關鍵字。這是我們建議的方法。

/* Opt-in the whole page to interpolate sizes to/from keywords */
:root {
    interpolate-size: allow-keywords; /* 👈 */
}

在以下示範中,我們會將這項規則加入程式碼。因此,從 width: auto 傳送至 width: auto 的動畫會正常運作 (在支援的瀏覽器中):

縮小選取器範圍,限制參與意願的觸及範圍

如果您想將 allow-keywords 選擇加入功能限制在文件的子樹狀結構中,請將選取器從 :root 調整為只選取您要指定的元素。舉例來說,如果網頁的 <header> 與這類轉場不相容,您可以將選擇加入的範圍限制在 <main> 元素及其子項,如下所示:

main { /* 👈 Scope the opt-in to only <main> and its descendants */
    interpolate-size: allow-keywords;
}

為什麼不預設允許動畫大小調整關鍵字?

針對這項選擇加入機制,常見的意見回饋是瀏覽器應只允許從內在大小關鍵字到長度的轉場和動畫,且預設為

我們在開發這項功能時,就研究過啟用這項行為的選項。工作小組發現,預設啟用這項功能無法向後相容,因為許多樣式表都假設內在大小關鍵字 (例如 automin-content) 無法製作動畫。如需詳細資訊,請參閱這篇 CSS Working Group 問題的評論

因此,這項屬性為選用屬性。由於繼承特徵,選擇整個文件只是在 :root 上宣告 interpolate-size: allow-sizes,如前文所述。

使用 calc-size() 以動畫方式與內用規模調整關鍵字

瀏覽器支援

  • Chrome:129。
  • Edge:129。
  • Firefox:不支援。
  • Safari:不支援。

資料來源

另一種啟用內在大小設定關鍵字內插的做法,是使用 calc-size() 函式。這可讓您以安全且明確的方式,對內在大小執行數學運算。

這個函式會依序接受兩個引數:

  • 計算大小依據,可以是 <intrinsic-size-keyword>,也可以是巢狀 calc-size()
  • 計算大小計算,可讓您使用計算大小基礎執行計算。如要參照卡路里大小,請使用 size 關鍵字。

例如:

width: calc-size(auto, size);        // = the auto width, unaltered
width: calc-size(min-content, size); // = the min-content width, unaltered

calc-size() 新增至原始示範,程式碼如下所示:

nav a {
    width: 80px;
    overflow-x: clip;
    transition: width 0.35s ease;

    &:hover,
    &:focus-visible {
        width: calc-size(max-content, size); /* 👈 */
    }
}

從視覺效果來看,結果與使用 interpolate-size 時完全相同。因此,在這種情況下,您應使用 interpolate-size

calc-size() 的優點在於可進行計算,而 interpolate-size 則無法執行這項操作:

width: calc-size(auto, size - 10px); // = The auto width minus 10 pixels
width: calc-size(min-content, size + 1rem); // = The min-content width plus 1rem
width: calc-size(max-content, size * .5);   // = Half the max-content width

舉例來說,如果您希望頁面上的所有段落都以最接近 50px 的倍數做為大小,可以使用以下方式:

p {
    width: calc-size(fit-content, round(up, size, 50px));
    height: calc-size(auto, round(up, size, 50px));
}

如果兩個 calc-size() 的計算大小基本相同,則 calc-size() 還可以讓您在兩個 calc-size() 之間插入內插。這也適用於使用 interpolate-size 達成的目標。

#element {
    width: min-content; /* 👈 */
    transition: width 0.35s ease;

    &:hover {
        width: calc-size(min-content, size + 10px); /* 👈 */
    }
}

為什麼不允許在 calc() 中使用 <intrinsic-size-keyword>

經常出現 calc-size() 的問題,是 CSS Working Group 未調整 calc() 函式來支援內建大小關鍵字的原因。

其中一個原因在於系統在計算時,禁止同時使用與上述規模相關的關鍵字組合。舉例來說,您可能會想編寫看起來有效的 calc(max-content - min-content),但實際上卻無效。calc-size() 會強制執行正確性,因為與 calc() 不同,它只接受單一 <intrinsic-size-keyword> 做為第一個引數。

另一個原因是情境感知。部分版面配置演算法會針對特定內在大小關鍵字執行特殊行為。calc-size() 是明確定義的內在大小,而非 <length>。因此,這些演算法可將 calc-size(<intrinsic-size-keyword>, …) 視為 <intrinsic-size-keyword>,並維持該關鍵字的特殊行為。

使用方法

在大多數情況下,請在 :root 上宣告 interpolate-size: allow-keywords。這是啟用內在大小關鍵字動畫的簡單方法,因為它基本上是單行程式碼。

/* Opt-in the whole page to animating to/from intrinsic sizing keywords */
:root {
    interpolate-size: allow-keywords; /* 👈 */
}

這段程式碼可漸進增強,不支援該程式碼的瀏覽器將改回使用不轉換。

如果您需要更精細的控制 (例如執行計算,或想使用 calc-size() 只能執行的操作),可以使用 calc-size()

#specific-element {
    width: 50px;

    &:hover {
        width: calc-size(fit-content, size + 1em); /* 👈 Only calc-size() can do this */
    }
}

不過,如果要在程式碼中使用 calc-size(),您必須為不支援 calc-size() 的瀏覽器加入備用方案。例如新增額外的大小宣告,或改用 @supports 進行功能偵測。

width: fit-content;
width: calc-size(fit-content, size + 1em);
       /* 👆 Browsers with no calc-size() support will ignore this second declaration,
             and therefore fall back to the one on the line before it. */

更多示範

以下是一些充分發揮 interpolate-size: allow-keywords 優點的示範。

通知

以下是這個 @starting-style 示範的分支。調整程式碼,讓系統可新增不同高度的項目。

為達到這項目的,整個網頁都會選擇使用大小關鍵字插補,而每個 .item 元素的 height 都會設為 auto。否則,程式碼與分支前完全相同。

:root {
    interpolate-size: allow-keywords; /* 👈 */
}

.item {
    height: auto; /* 👈 */

    @starting-style {
        height: 0px;
    }
}

<details> 元素設定動畫

您會想使用這類插補的典型用途,是為展開式小工具或專屬摺疊式選單製作動畫。在 HTML 中,您可以使用 <details> 元素來執行這項操作。

有了 interpolate-size: allow-keywords,您可以執行以下操作:

@supports (interpolate-size: allow-keywords) {
    :root {
        interpolate-size: allow-keywords;
    }
    
    details {
        transition: height 0.5s ease;
        height: 2.5rem;
        
        &[open] {
            height: auto;
            overflow: clip; /* Clip off contents while animating */
        }
    }
}

不過,您可以看到,動畫只會在展開小工具開啟時執行。為因應這項需求,Chrome 正在開發 ::details-content 擬似元素,並將於今年稍晚在 Chrome 中推出 (日後的文章將會介紹這項元素)。結合 interpolate-size: allow-keywords::details-content 後,就可以產生雙向動畫: