1487 字
7 分鐘

CSS transition-behavior 怎麼用?用 allow-discrete 做 display 的進出場轉場

只對 opacity 做轉場時,元素雖然會淡出,display: nonecontent-visibility: hidden 卻常常讓內容直接從畫面消失。transition-behavior: allow-discrete 的用途,就是允許這類不會連續插值的離散屬性參與 transition。

直接答案是:display 放進 transition property,搭配非零的 duration,再用 allow-discrete 開啟離散轉場;需要進場動畫時,另外用 @starting-style 指定初始狀態。 它不是把 display 變成可逐幀計算的數值,而是讓瀏覽器在轉場期間保留元素,再在適當時間切換值。

allow-discrete 先解決什麼問題#

transition-behavior 只有和其他 transition 設定一起使用才有作用,至少要有要轉場的屬性和非零 duration。最小的卡片範例如下:

.card {
opacity: 1;
display: block;
transition-property: opacity, display;
transition-duration: 0.25s;
transition-behavior: allow-discrete;
}
.card.is-hidden {
opacity: 0;
display: none;
}

在支援 allow-discrete 的瀏覽器裡,卡片會先完成 opacity 的淡出,再切換成 display: none。進場時則會先變成可見,再開始 opacity 的轉場;離散值本身不是從 block 慢慢變成 none

如果要用 shorthand,可以保留一條不含新值的 fallback,再覆蓋一條支援離散屬性的宣告:

.card {
transition: opacity 0.25s ease;
transition: opacity 0.25s ease, display 0.25s allow-discrete;
}

不支援第二條宣告的瀏覽器會保留第一條,至少仍能讓 opacity 轉場;支援的瀏覽器才會把 display 納入轉場。

離散屬性不是一般的漸變#

一般離散屬性通常會在轉場中間點切換,但 display: nonecontent-visibility: hidden 有特別處理,讓內容在整段動畫期間仍可見:

方向瀏覽器何時切換使用者看到的結果
none → 可見值動畫開始時切換元素從一開始就能淡入或變形
可見值 → none動畫結束時切換元素完整淡出後才從版面移除

這也是為什麼只寫 opacity: 0 不夠:元素仍可能佔據版面、仍可能接收互動,或在隱藏後留下一個不可預期的焦點位置。把 visual transition 和 layout/accessibility 狀態一起設計,才是 allow-discrete 的實際用途。

@starting-style 做進場動畫#

元素第一次從 display: none 變成可見時,瀏覽器不一定會自動觸發你期待的 entry transition。@starting-style 可以明確告訴瀏覽器:進場前要從哪個狀態開始。

.panel {
opacity: 0;
display: none;
transform: translateY(-0.5rem);
transition:
opacity 0.2s ease,
transform 0.2s ease,
display 0.2s allow-discrete;
}
.panel.is-open {
opacity: 1;
display: block;
transform: translateY(0);
}
@starting-style {
.panel.is-open {
opacity: 0;
transform: translateY(-0.5rem);
}
}

@starting-style 只處理 entry 的起點,不會替你管理開關狀態。按鈕、JavaScript 或元件框架仍要正確切換 class;如果內容有表單或可聚焦控制項,也要在開啟與關閉時處理 focus。

Popover 進出場要加上 display 與 overlay#

原生 Popover API 已經負責顯示、關閉和 top layer;如果你要替 popover 加上進出場效果,還要把 displayoverlay 一起列入 transition,避免元素太早被隱藏或移出 top layer。你可以先閱讀 HTML Popover API 的基本用法,再套用下面的樣式:

<button type="button" popovertarget="help-popover">顯示說明</button>
<div id="help-popover" popover="auto">這是一段可關閉的說明。</div>
#help-popover {
opacity: 0;
transform: scale(0.96);
transition:
opacity 0.2s ease,
transform 0.2s ease,
overlay 0.2s allow-discrete,
display 0.2s allow-discrete;
}
#help-popover:popover-open {
opacity: 1;
transform: scale(1);
}
@starting-style {
#help-popover:popover-open {
opacity: 0;
transform: scale(0.96);
}
}

display 讓 popover 在淡出期間保持可見,overlay 則讓它留在 top layer 到轉場完成。這個例子是 progressive enhancement:不支援相關能力的瀏覽器仍應能開關 popover,但不一定有完整的動畫效果。

用 feature query 和 reduced motion 做退路#

如果你的瀏覽器支援矩陣包含較舊的裝置,可以把 enhancement 集中在 @supports,並對偏好減少動畫的使用者降低 duration:

.card {
opacity: 1;
display: block;
transition: opacity 0.2s ease;
}
@supports (transition-behavior: allow-discrete) {
.card {
transition:
opacity 0.2s ease,
display 0.2s allow-discrete;
}
}
@media (prefers-reduced-motion: reduce) {
.card {
transition-duration: 0.01ms;
}
}

不要用 @supports 來隱藏整個內容;它只應控制轉場 enhancement。就算沒有離散轉場,開關功能和文字內容仍要可用。

上線前檢查這四件事#

  1. 狀態:關閉後的元素是否真的從版面、互動與輔助技術的閱讀順序移除?
  2. 焦點:關閉一個含有輸入框的 panel 或 popover 後,焦點是否回到觸發按鈕或合理的下一個控制項?
  3. 支援:在目標瀏覽器測試 display@starting-style、Popover top layer 和 overlay,不要只在最新桌面瀏覽器確認。
  4. 偏好:開啟 prefers-reduced-motion 後,內容是否仍然能快速出現與消失,而不會讓使用者等待動畫。

常見錯誤是只加 transition-behavior: allow-discrete 卻沒有把 display 放進 transition-property,或沒有設定 duration。另一個錯誤是先用 JavaScript 設成 display: none,動畫根本沒有機會執行;狀態切換要交給 CSS 與元件生命週期協調。

結論:把顯示狀態和轉場一起設計#

allow-discrete 的價值不是讓離散屬性變成連續動畫,而是把「可見、可互動、從版面移除」這些狀態交給同一段轉場協調。一般卡片用 displayopacity,進場補上 @starting-style;Popover 則把 displayoverlay 和 top layer 一起處理,再用 feature query 和 reduced motion 保留可用退路。

常見問題#

Q: transition-behavior 會讓 display 平滑地變成 none 嗎?#

A: 不會。display 仍是離散值,瀏覽器會在特定時間點切換;對 none 的進出場,重點是讓元素在整段 opacity 或 transform 動畫期間保持可見。

Q: 為什麼有 allow-discrete 還需要 @starting-style#

A: allow-discrete 負責允許離散屬性參與轉場,@starting-style 則指定元素第一次進場時的起始樣式。兩者處理不同問題,不能互相取代。

Q: Popover 只寫 opacity 轉場會怎樣?#

A: 它可能在淡出開始時就因 display: none 或離開 top layer 而消失,看不到完整動畫。要讓進出場穩定,應依支援範圍把 displayoverlay@starting-style 一起測試。

參考資料:

MDN:transition-behavior CSS property

MDN:Popover API

CSS transition-behavior 怎麼用?用 allow-discrete 做 display 的進出場轉場
https://laplusda.com/posts/css-transition-behavior-allow-discrete/
作者
Zero
發佈於
2026-08-08
許可協議
CC BY-NC-SA 4.0
這篇文章有幫助嗎?

回報錯字、失效連結,或告訴我你想看的延伸主題。