CSS transition-behavior 怎麼用?用 allow-discrete 做 display 的進出場轉場
只對 opacity 做轉場時,元素雖然會淡出,display: none 或 content-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: none 和 content-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 加上進出場效果,還要把 display 和 overlay 一起列入 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。就算沒有離散轉場,開關功能和文字內容仍要可用。
上線前檢查這四件事
- 狀態:關閉後的元素是否真的從版面、互動與輔助技術的閱讀順序移除?
- 焦點:關閉一個含有輸入框的 panel 或 popover 後,焦點是否回到觸發按鈕或合理的下一個控制項?
- 支援:在目標瀏覽器測試
display、@starting-style、Popover top layer 和overlay,不要只在最新桌面瀏覽器確認。 - 偏好:開啟
prefers-reduced-motion後,內容是否仍然能快速出現與消失,而不會讓使用者等待動畫。
常見錯誤是只加 transition-behavior: allow-discrete 卻沒有把 display 放進 transition-property,或沒有設定 duration。另一個錯誤是先用 JavaScript 設成 display: none,動畫根本沒有機會執行;狀態切換要交給 CSS 與元件生命週期協調。
結論:把顯示狀態和轉場一起設計
allow-discrete 的價值不是讓離散屬性變成連續動畫,而是把「可見、可互動、從版面移除」這些狀態交給同一段轉場協調。一般卡片用 display 加 opacity,進場補上 @starting-style;Popover 則把 display、overlay 和 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 而消失,看不到完整動畫。要讓進出場穩定,應依支援範圍把 display、overlay 和 @starting-style 一起測試。
參考資料:
回報錯字、失效連結,或告訴我你想看的延伸主題。