4 項新的 CSS 功能,讓你享受流暢的進入及離開動畫效果

尤娜.克雷維茲 (Una Kravets)
Una Kravets
喬伊阿哈爾
Joey Arhar

動作是所有數位體驗的核心,可引導使用者從一次互動開始。但是在網路平台上的流暢動畫仍然會出現一些缺漏。包括能夠輕鬆為進入和離開動畫建立動畫效果,以及流暢地在頂層和跳出的可關閉元素 (例如對話方塊和彈出式視窗) 建立動畫。

為填補這些差異,Chrome 116 和 117 包含四項全新的網路平台功能,可針對獨立屬性提供流暢的動畫和轉場效果。

這四項新功能包括:

  • 可在主要畫面格時間軸上為 displaycontent-visibility 加上動畫效果 (自 Chrome 116 版起)。
  • transition-behavior 屬性搭配 allow-discrete 關鍵字,用來啟用 display 等獨立屬性 (從 Chrome 117 版起)。
  • 根據 @starting-style 規則,為 display: none 和頂層 (自 Chrome 117 版) 的進入效果建立動畫效果。
  • overlay 屬性用於控制動畫期間的頂層行為 (從 Chrome 117 版開始)。 ## 在主要畫面格顯示動畫

自 Chrome 116 起,您可以在主要畫面格規則中使用 displaycontent-visibility。然後在主要畫面格發生時切換這些屬性。無需其他新值即可支援這個做法:

.card {
  animation: fade-out 0.5s forwards;
}

@keyframes fade-out {
  100% {
    opacity: 0;
    display: none;
  }
}

上述範例說明如何以 0.5 秒持續時間為不透明度設定動畫效果,然後將顯示設定設為無。此外,forwards 關鍵字可確保動畫維持其結束狀態,讓套用該動畫的元素仍維持 display: noneopacity: 0

這個簡單的範例會模擬轉換後的功能 (請參閱轉換一節中的示範)。但轉場效果無法建立更複雜的動畫,例如以下範例:

.card {
  animation: spin-and-delete 1s ease-in forwards;
}

@keyframes spin-and-delete {
  0% {
    transform: rotateY(0);
    filter: hue-rotate(0);
  }
  80% {
    transform: rotateY(360deg);
    filter: hue-rotate(180deg);
    opacity: 1;
  }
  100% {
    opacity: 0;
    display: none;
  }
}

spin-and-delete 動畫是結束動畫。首先,資訊卡會在 Y 軸上旋轉,通過色調旋轉,然後在 80% 到時間軸時,將不透明度從 1 轉換成 0。最後,卡片會從 display: block 切換為 display: none

針對這些結束動畫,您可以設定動畫觸發條件,而不是直接套用至元素。舉例來說,只要將事件監聽器附加至按鈕,即可觸發類別套用動畫,如下所示:

.spin-out {
   animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
 document.querySelector('.card').classList.add('spin-out');
})

上述範例現在的結束狀態為 display:none。在許多情況下,您可能會想進一步移除設有逾時的 DOM 節點,好讓動畫先完成。

轉換離散動畫

不同於為獨立的屬性和主要畫面格建立動畫效果時,您必須使用 allow-discrete 轉換行為模式才能轉換獨立的屬性。

transition-behavior 屬性

allow-discrete 模式是 transition-behavior 屬性的值,可以建立獨立轉換。transition-behavior 接受兩個值:normalallow-discrete

.card {
  transition: opacity 0.25s, display 0.25s;
  transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}

.card.fade-out {
  opacity: 0;
  display: none;
}
注意:這個轉場示範示範的技巧與第一個動畫示範不同,但外觀看起來很相似。

transition 簡寫也會設定這個值,因此您可以省略該屬性,並改為針對每個轉場效果在 transition 簡寫結尾使用 allow-discrete 關鍵字。

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

.card.fade-out {
  opacity: 0;
  display: none;
}

如果要為多個獨立屬性建立動畫效果,您必須在每個要建立動畫的屬性後方加上 allow-discrete。例如:

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

項目動畫的 @starting-style 規則

本文到目前為止已介紹結束動畫,可供您建立需要使用 @starting-style 規則的進入動畫。

使用 @starting-style 套用樣式,瀏覽器可在網頁開啟元素前查詢的樣式。這是「開啟前」狀態 (也就是建立動畫的位置)。

/*  0. BEFORE-OPEN STATE   */
/*  Starting point for the transition */
@starting-style {
  .item {
    opacity: 0;
    height: 0;
  }
}

/*  1. IS-OPEN STATE   */
/*  The state at which the element is open + transition logic */
.item {
  height: 3rem;
  display: grid;
  overflow: hidden;
  transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}

/*  2. EXITING STATE   */
/*  While it is deleting, before DOM removal in JS, apply this
    transformation for height, opacity, and a transform which
    skews the element and moves it to the left before setting
    it to display: none */
.is-deleting {
  opacity: 0;
  height: 0;
  display: none;
  transform: skewX(50deg) translateX(-25vw);
}

現在,這些 TODO 清單項目同時擁有進入和結束狀態:

為元素與頂層建立動畫效果

如要為頂層與頂層建立元素動畫效果,請指定「開啟」狀態的 @starting-style,告知瀏覽器動畫來源。對話方塊的開啟狀態是使用 [open] 屬性定義。如果是彈出式視窗,請使用 :popover-open 虛擬類別。

簡單的對話方塊範例可能如下所示:

/*   0. BEFORE-OPEN STATE   */
@starting-style {
  dialog[open] {
    translate: 0 100vh;
  }
}

/*   1. IS-OPEN STATE   */
dialog[open] {
  translate: 0 0;
}

/*   2. EXIT STATE   */
dialog {
  transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
  translate: 0 100vh;
}

在下一個範例中,進入和離開效果並不相同。從可視區域底部向上滑動即可進入可視區域,讓效果離開可視區域頂端。它也可使用巢狀 CSS 編寫,以疊加更多視覺元素。

為彈出式視窗建立動畫時,請使用 :popover-open 虛擬類別,而非之前使用的 open 屬性。

.settings-popover {
  &:popover-open {
    /*  0. BEFORE-OPEN STATE  */
    /*  Initial state for what we're animating *in* from, 
        in this case: goes from lower (y + 20px) to center  */
    @starting-style {
      transform: translateY(20px);
      opacity: 0;
    }
    
    /*  1. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;
  }
  
  /*  2. EXIT STATE  */
  /*  Initial state for what we're animating *out* to , 
      in this case: goes from center to (y - 50px) higher */
  transform: translateY(-50px);
  opacity: 0;
  
  /*  Enumerate transitioning properties, 
      including display and allow-discrete mode */
  transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}

overlay 個房源

最後,如要從頂層淡出 popoverdialog,請在轉場效果清單中新增 overlay 屬性。popoverdialog 會逸出祖系片段和轉換,並將內容放在頂層。如未轉換 overlay,元素會立即回到裁剪、轉換及覆蓋,且不會出現轉場效果。

[open] {
  transition: opacity 1s, display 1s allow-discrete;
}

請改為在轉場或動畫中加入 overlay,以為 overlay 和其他地圖項目加上動畫效果,並在動畫效果時確保其停留在頂層。看起來會更加順暢。

[open] {
  transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}

此外,如果在頂層開啟多個元素,疊加畫面可協助您控制上層和退出圖層的流暢轉換效果。您可以在這個簡易範例中查看不同之處。如果在轉換過程中,沒有將 overlay 套用至第二個彈出式視窗,系統會在開始轉換之前,先從頂層彈出式視窗移開,然後跳轉至另一個彈出式視窗。這並非流暢的效果。

關於檢視畫面轉場效果的注意事項

如果要調整 DOM,例如從 DOM 新增及移除元素,另一個流暢動畫的視覺效果是檢視轉場效果。以下是兩個使用檢視轉場效果建立的範例。

在第一個示範中,檢視畫面轉換將處理轉換作業,而不會設定 @starting-style 和其他 CSS 轉換。檢視畫面轉換的設定方式如下:

首先,在 CSS 中,為每張資訊卡提供個別的 view-transition-name

.card-1 {
  view-transition-name: card-1;
}

.card-2 {
  view-transition-name: card-2;
}

/* etc. */

然後,在 JavaScript 中,納入 DOM 異動 (本例中為移除卡片) 並在檢視轉換中納入。

deleteBtn.addEventListener('click', () => {
  // Check for browser support
  if (document.startViewTransition) {
    document.startViewTransition(() => {
      // DOM mutation
      card.remove();
    });
  } 
  // Alternative if no browser support
  else {
    card.remove();
  }
})

現在,瀏覽器可以將每張卡片的淡出和變形處理至新的位置。

另一個可行的例子是「新增/移除清單項目」示範。在此情況下,請務必為已建立的每張卡片新增專屬的 view-transition-name

結語

這些新的平台功能讓我們能更順利地在網路平台上進入及結束動畫。詳情請點選以下連結: