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

動態效果是任何數位體驗的核心元素,可引導使用者從一個互動流程轉到下一個。不過,在網頁平台上,流暢的動畫效果會出現一些空白。這包括輕鬆為進入和離開動畫加入動畫效果,以及為對話方塊和彈出式視窗等可關閉元素,提供順暢的進入和離開動畫效果。

為彌補這些缺口,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 秒的時間內將不透明度動畫設為 0,然後將顯示狀態設為無。此外,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. 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;
}

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

/*  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);
}

您現在已為這些待辦事項清單項目設定了進入和離開狀態:

為元素建立頂層動畫和從頂層動畫

如要為元素設定進出頂層的動畫,請在「open」狀態上指定 @starting-style,告訴瀏覽器動畫的起點。對話方塊的開啟狀態會使用 [open] 屬性定義。如要使用彈出式視窗,請使用 :popover-open 虛擬類別。

對話方塊的簡單範例如下:

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

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

/*   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. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;

    /*  1. 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;
    }
  }
  
  /*  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 與其他功能一同顯示動畫,並確保動畫播放時,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

結論

這些全新的平台功能,讓我們更接近在網頁平台上打造流暢的進入和離開動畫。如要進一步瞭解,請參閱下列連結: