Day18 純 CSS DVD 反彈動畫

今天我們要使用純 CSS 實現 DVD 反彈動畫,讓大家認識 steps() 以及 animation-composition 屬性的使用方式,並提供這個實用的應用。(應該吧...)

HTML

HTML,簡單

1<div></div>

CSS

版面

CSS 我們先不放背景圖片,用正方形就好了。用這種深藍色整個味道都出來了XD。<body> 設定 overflow: hidden; 是因為有時候反彈時會撞出滾動條,看起來不是很舒服。

 1body {
 2  background: #000;
 3  overflow: hidden;
 4}
 5
 6div {
 7  width: 100px;
 8  height: 100px;
 9  background: blue;
10}

動畫

我們分析一下,DVD 反彈動畫需要的動畫

  • 水平移動 - translateX()
  • 垂直移動 - translateY()
  • 水平碰撞時改變顏色
  • 垂直碰撞時改變顏色

移動動畫

我們先來實現水平移動,我們使用 translateX() 來實現,並且使用 animation 屬性來實現動畫。因為元素定位點是在左上角,所以我們需要記得移動到 100vw - 100% 的位置就可以了。

transform:translate() 的百分比是相對於自己的寬高計算的,所以我們可以使用 100% 來表示自己的寬高。

1@keyframes horizontal {
2  from {
3    transform: translateX(0);
4  }
5  to {
6    transform: translateX(calc(100vw - 100%));
7  }
8}

OK沒問題。那垂直的也加上去。兩個時間故意設定稍微不一樣,讓路線隨機一點。

 1div {
 2  width: 100px;
 3  height: 100px;
 4  background: blue;
 5  animation: horizontal 2.6s infinite linear alternate,
 6    vertical 2s infinite linear alternate;
 7}
 8
 9@keyframes horizontal {
10  from {
11    transform: translateX(0);
12  }
13  to {
14    transform: translateX(calc(100vw - 100%));
15  }
16}
17@keyframes vertical {
18  from {
19    transform: translateY(0);
20  }
21  to {
22    transform: translateY(calc(100vh - 100%));
23  }
24}

欸等等,垂直移動效果加上去之後,水平移動的效果就沒了!因為兩個都是使用 transform 屬性,所以其中一個被蓋過去了。但我們的動畫是要同時執行,變色動畫都還沒加上去啊!在之前常見的解決方法有

  • 使用 topleft 屬性代替 transform 屬性
  • 外面再包一層 div,讓 兩個 div 同時移動

而今天我們有一個更加優雅的解決方法,就是使用 animation-composition 屬性,讓兩個動畫同時執行。我們給 div 加上 animation-composition 屬性,並且設定 accumulate 值。

1    animation-composition: accumulate;

呼~救回來了,但是我們的動畫還沒有變色,我們來加上變色的動畫。

變色動畫

我們使用 filter 屬性來實現,filter 屬性有一個 hue-rotate() 函式,可以讓顏色旋轉,我們使用 hue-rotate(360deg) 來讓顏色旋轉一圈,就可以讓顏色變回原本的顏色了,讓所有顏色都可以跑過一次。

顏色改變的動畫長度記得要是平移動畫長度的倍數,才可以在撞牆時剛好變色。

複習: Day7 幫我開濾鏡 filter

 1div{
 2/* 同上 */
 3    animation: 
 4        horizontal 2.6s infinite linear alternate,
 5        vertical 2s infinite  linear alternate,
 6        colorX 26s infinite,
 7        colorY 14s infinite;
 8    animation-composition: accumulate;
 9}
10
11@keyframes colorX {
12    to {
13        filter: hue-rotate(360deg);
14    }
15}
16@keyframes colorY {
17    to {
18        filter: hue-rotate(360deg);
19    }
20}

怎麼說呢,顏色是漸漸變而不是直接變,這樣看起來就不是很像 DVD 動畫了。而這個時候我們就要拿出 step()steps() 是一個可以讓動畫在指定時間內,依照指定的步數來執行的函式,而不是漸變。中間可以填入數字代表中間要經過幾個顏色。

1     animation: 
2        horizontal 2.6s infinite linear alternate,
3        vertical 2s infinite  linear alternate,
4        colorX 26s infinite steps(10),
5        colorY 14s infinite steps(7);

DVD 圖片

最後換成 DVD 的圖片。從維基百科抓 svg 向量圖...結果...

甚麼都看不到。原因是 Logo 的背景是黑色的。你可以使用我製作的這個圖示上色 CSS濾鏡生成器,透過 filter 屬性來改變 Logo 的顏色。把它貼上到動畫中,並在後面的hue-rotate() 屬性中加上360度就可以囉。

1@keyframes colorX {
2  from{
3    filter: invert(9%) sepia(84%) saturate(5931%) hue-rotate(245deg) brightness(116%) contrast(153%);
4  }
5  to {
6    filter: invert(9%) sepia(84%) saturate(5931%) hue-rotate(605deg) brightness(116%) contrast(153%);
7  }
8}

成果如下

https://codepen.io/edit-mr/pen/abPjjMd

1<img src="https://upload.wikimedia.org/wikipedia/commons/9/9b/DVD_logo.svg">
 1body {
 2  background: #000;
 3  overflow: hidden;
 4}
 5
 6img {
 7  width: 100px;
 8  animation: horizontal 2.6s infinite linear alternate,
 9    vertical 2s infinite linear alternate, colorX 26s infinite steps(10),
10    colorY 14s infinite steps(7);
11  animation-composition: accumulate;
12}
13@keyframes horizontal {
14  from {
15    transform: translateX(0);
16  }
17  to {
18    transform: translateX(calc(100vw - 100%));
19  }
20}
21@keyframes vertical {
22  from {
23    transform: translateY(0);
24  }
25  to {
26    transform: translateY(calc(100vh - 100%));
27  }
28}
29@keyframes colorX {
30  from {
31    filter: invert(9%) sepia(84%) saturate(5931%) hue-rotate(245deg)
32      brightness(116%) contrast(153%);
33  }
34  to {
35    filter: invert(9%) sepia(84%) saturate(5931%) hue-rotate(605deg)
36      brightness(116%) contrast(153%);
37  }
38}
39@keyframes colorY {
40  from {
41    filter: invert(9%) sepia(84%) saturate(5931%) hue-rotate(245deg)
42      brightness(116%) contrast(153%);
43  }
44  to {
45    filter: invert(9%) sepia(84%) saturate(5931%) hue-rotate(605deg)
46      brightness(116%) contrast(153%);
47  }
48}

以上就是我今天的分享,歡迎在 InstagramGoogle 新聞追蹤毛哥EM資訊密技,也歡迎訂閱我新開的YouTube頻道:網棧

我是毛哥EM,讓我們明天再見。

參考資料: ChokCoco | MDN

Posts in this Series