最近在練習使用 CSS 來製作一些簡單的動畫,以下是我收集資料與實作的成果。
製作一張可以水平翻轉的卡片,這邊會使用 Vue.js 來簡化邏輯,主要是解釋 CSS 的部分。
首先,一張卡片會有正面與反面,程式碼的寫法會是:
<div class="flip-card">
<div class="flip-card-inner">
<div class="flip-card-front">
<button class="flip-card-btn">flip</button>
<h2>Front</h2>
</div>
<div class="flip-card-back">
<button class="flip-card-btn">flip</button>
<h2>Back</h2>
</div>
</div>
</div>
接下來就要設定 CSS:
/* 設定轉動時透視狀態 */
.flip-card {
perspective: 1000px;
}
/* 卡片以 3D 方式呈現 */
.flip-card-inner {
position: relative;
transform-style: preserve-3d;
transition: transform 1s;
transition-timing-function: ease-in-out;
}
/* 卡片翻轉 */
.flip-card-inner.flipped {
transform: rotateY(180deg);
transition: ease-in-out 1s;
}
/* 卡片內容樣式設定 */
.flip-card-front,
.flip-card-back {
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden; /* Safari */
backface-visibility: hidden;
}
/* 卡片背面翻轉 */
.flip-card-back {
transform: rotateY(180deg);
}
以下會說明每個 CSS 屬性存在的目的,如果沒有特殊的情境,每個屬性都只會解釋一次,裡面的數值可根據自己需求改變。
perspective
:是 Transform 3D 會用到的屬性,表示 Z軸到觀看者之間的距離。數值越小越容易會有翻轉失真的問題,這是因為觀測者與卡片距離太相近,導致卡片翻轉時超出了觀測者的範圍,所以這邊設定 1000px
(可以試著將數值調低來觀看差異)
這裡會把 .flip-card-inner
和 .flip-card-inner.flipped
放在一起說:
.flip-card-inner
:
transform-style: preserve-3d
將這個元件保留在 3D 空間中transition
:翻轉的方式會參照 .flip-card-inner.flipped
裡 transform
的設定transition-timing-function
:動畫過渡的方式.flip-card-inner.flipped
:
transform: rotateY(180deg)
:當觸發翻轉時,會水平翻轉 180 度transition
:動畫過渡的方式與時間backface-visibility: hidden;
:是將卡片背面的物件隱藏。也因為現在是在 3D 空間下,所以可以看到多出一個 .flip-card-back
裡的設定,這就是將內容設定成卡背的方式
這邊要特別注意,為什麼使用 position: absolute
?這是因為backface-visibility
是將卡片背後的內容 hidden
,這表示這個元素還是存在,如果不使用 absolute
在卡片翻過去背面後,卡片正面的內容雖然消失但依舊會佔據原本的位置。
以 Vue 來說很簡單,只要設定一個 Reactive State 就可以解決:
const isFlipped = ref(false);
const flipCard = () => {
isFlipped.value = !isFlipped.value;
};
再將這個 flipCard
函式套用在想與之互動的方式上(可以是 hover 之類的,這裡我用 button):
<button class="flip-card-btn" @click="flipCard()">
flip
</button>