iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
Modern Web

Super Easy CSS,極度簡單 PART 3!讓想像躍然於螢幕之上系列 第 17

#80 Display: none 也可以做 CSS Transition 動畫了?@starting-style 與 transition-behavior: allow-discrete

  • 分享至 

  • xImage
  •  

想要 UI 出現時,不只是生硬地「出現」嗎?今天我們要來研究兩個 CSS 的新語法:@starting-styletransition-behavior: allow-discrete。他們是專門解決那些從 display: none 這類狀態做成動畫的困境。

本篇同步發表於我的 Hashnode 部落格:
Eva Chen | 網頁設計師下班後 (hashnode.dev)


一、為什麼會有這兩個新屬性?

過去在網頁開發中,要為一個從 display: none(完全隱藏)變成可見狀態(例如 display: block)的元素加上轉場動畫,是一件不可能的事。

因為 display 屬性本身是「離散的 (discrete)」,意思是要嘛 none 要嘛 block,沒有中間值可以讓瀏覽器去計算動畫的漸變過程。所以,當你改變 display 屬性時,UI 元素就會瞬間出現或消失,無法套用 transition 來產生平滑的動畫。

為了解決這個長久以來的難題,CSS 推出了 @starting-styletransition-behavior: allow-discrete 這兩個好幫手。


二、@starting-style:定義動畫的「起點」

@starting-style 是一個新的 CSS at-rule,它的作用是告訴瀏覽器,當一個 UI 元素首次渲染或從 display: none 狀態改變時,它的初始樣式是什麼。可以把它想像成是為動畫提供一個「前置狀態」或「起點」。

少了這個「起點」,瀏覽器就不知道該從何開始播放動畫,這就是為什麼以往直接對 display: none 的元素做轉場會失敗的原因。

如何使用 @starting-style

你可以將它寫在既有的 CSS 規則裡面,也可以獨立出來寫。為了確保起始樣式能被正確應用,建議將 @starting-style 寫在元素原本的樣式規則之後。

範例:

/* 獨立使用 */
@starting-style {
    .my-element {
        opacity: 0;
        transform: scale(0.8);
    }
}

.my-element {
    opacity: 1;
    transform: scale(1);
    transition: opacity 0.5s, transform 0.5s;
}

/* 也可以巢狀在現有規則內 */
.my-element {
    opacity: 1;
    transform: scale(1);
    transition: opacity 0.5s, transform 0.5s;

    @starting-style {
        opacity: 0;
        transform: scale(0.8);
    }
}

這樣的結果是:在這個 .my-element 載入時,會有一個淡出兼放大的動畫:

DEMO 連結:CSS @starting-style


二、transition-behavior: allow-discrete:讓「離散」屬性動起來

這個屬性的作用就如同它的名字一樣,允許 transition 去影響那些「離散的」CSS 屬性,其中最重要的就是 display

當你為 transition-property 加上 display,並設定 transition-behavior: allow-discrete 後,瀏覽器就能夠讓轉場動畫能夠完整呈現。

transition-behavior 有兩個值:

  • normal (預設值): 不會對離散屬性產生轉場效果。

  • allow-discrete: 允許對離散屬性產生轉場效果。


三、DEMO

那就讓我們來看一起搭配使用會怎麼樣?尤其是在處理像彈出視窗 (popover)、對話框 (dialog) 等需要顯示和隱藏的元件時。

讓我們來看一個實際的例子,我們來改寫之前寫過 :target 光箱的例子,不過改成用 JS 控制 Class 做狀態的調整。而 transition-behavior: allow-discrete 應用在 display: nonedisplay: flex 的切換:

DEMO 連結:Pure CSS Lightbox by transition-behavior: allow-discrete

.lightbox {
    /* 預設狀態:完全隱藏 */
    display: none;
    opacity: 0;
    
    /* 設定過渡動畫 */
    transition: opacity 0.3s;
    transition-behavior: allow-discrete;
}

/* 開啟狀態:讓元素可見並完全不透明 */
.lightbox.is-open {
    display: flex;
    opacity: 1;
}

/* 關閉中狀態:讓元素保持可見,但變為透明以觸發退場動畫 */
.lightbox.is-closing {
    display: flex; /* 關鍵:在動畫期間保持 display: flex */
    opacity: 0;
}

/* 定義 .is-open 狀態的入場動畫起始點 */
@starting-style {
    .lightbox.is-open {
        opacity: 0;
    }
}

運作原理剖析

  1. 點擊關閉按鈕

    • JavaScript 執行,它會移除 .is-open新增 .is-closing

    • 此時 Lightbox 的狀態從 opacity: 1 變為 opacity: 0

    • 最關鍵的一步:因為 .is-closing class 裡有 display: flex;,所以 Lightbox 在動畫期間並不會馬上消失,它仍然佔據著頁面空間。

  2. 播放退場動畫

    • 瀏覽器偵測到 opacity 的變化,並且因為元素仍然是 display: flex,所以會順利地播放從 1 到 0 的淡出動畫。
  3. 動畫結束

    • JavaScript 中的 setTimeout 在等待了 300 毫秒後執行。

    • 它會移除 .is-closing class

    • 現在 Lightbox 身上沒有任何狀態 class,它的樣式退回到最原始的 .lightbox 規則,也就是 display: none,此時它才真正地從畫面中消失。


這兩個語法真的讓以前不可能做到的事做到了!

不過目前 Firefox 還未支援(transition-behavior: allow-discrete 的部分),但是還是可以值得期待!
詳細請看 Can I Use( @starting-style / transition-behavior: allow-discrete)。

延伸閱讀:


↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

感謝看到最後的你,若你覺得獲益良多,請不要吝嗇給我按個喜歡。❤️

如果你喜歡我的創作,還想看看其他有趣的分享與日常,
可以追蹤我的 IG @im1010ioio,或者是🧋送杯珍奶鼓勵我,謝謝你🥰。

Eva Chen 送杯珍奶鼓勵我


上一篇
#79 告別 JS 計算位置!CSS Anchor Positioning 定位的新寫法
下一篇
#81 CSS 可以寫三角函數?sin()、cos()、tan() 專門處理圓弧、波浪或是特殊角度
系列文
Super Easy CSS,極度簡單 PART 3!讓想像躍然於螢幕之上24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言