iT邦幫忙

2025 iThome 鐵人賽

DAY 20
2
Modern Web

關於那些有趣的 CSS 效果系列 第 20

( Day 20 ) 純 CSS 製作圓點載入動畫 ( 陰影動畫 )

  • 分享至 

  • xImage
  •  

回想起之前參觀的草間彌生特展,那些充滿生命力和精神幻想的圓點,讓我想起董志成惟妙惟肖的模仿了「草間彌生」!因此我覺得應該要用純 CSS 做個圓點效果,致敬一下草間彌生!

純 CSS 製作圓點載入動畫 ( 陰影動畫 )

正文開始

這個範例教學會使用 CSS box-shadow 的陰影樣式,讓單一個 div 的多重陰影在畫面中產生十六個圓點,並搭配自訂屬性 @property 和動畫 animation 讓陰影動起來,實作漂亮的圓點載入動畫。

CSS 教學 - CSS 製作圓點載入動畫 ( 陰影動畫 )

多重陰影產生十六個圓點

box-shadow 陰影樣式屬性撰寫多種陰影樣式,就能做出多重陰影的效果,運用三角函數公式,就能將這些陰影定位在一個圓的圓周上,舉例來說,當一個圓的半徑為 50px,就能產生下方的座標點:

javascript >>>>
(50px, 0px)         
(46.20px, 19.14px)    // 50px * cos(22.5deg), 50px * sin(22.5deg) 
(35.36px, 35.36px)    // (50px * cos(45deg), 50px * sin(45deg))  
(19.14px, 46.20px)    // (50px * cos(67.5deg), 50px * sin(67.5deg))  
(0px, 50px)
(-19.14px, 46.20px)   // 50px * cos(112.5deg), 50px * sin(112.5deg)
(-35.36px, 35.36px)   // 50px * cos(135deg), 50px * sin(135deg)
(-46.20px, 19.14px)   // 50px * cos(157.5deg), 50px * sin(157.5deg)
(-46.20px, -19.14px)  // 50px * cos(202.5deg), 50px * sin(202.5deg) 
(-35.36px, -35.36px)  // 50px * cos(225deg), 50px * sin(225deg)
(-19.14px, -46.20px)  // 50px * cos(247.5deg), 50px * sin(247.5deg)
(0px, -50px)
(19.14px, -46.20px)   // 50px * cos(292.5deg), 50px * sin(292.5deg)
(35.36px, -35.36px)   // 50px * cos(315deg), 50px * sin(315deg)
(46.20px, -19.14px)   // 50px * cos(337.5deg), 50px * sin(337.5deg)

將這些座標點改成 CSS 的寫法,使用透明色隱藏元素本身,畫面中就會出現十六個透過陰影產生的圓點。

<!-- HTML 程式碼 -->
<div class="c"></div>

<!-- CSS 程式碼 -->
<style>
  .c {
    position: absolute;
    top: 100px;
    left: 100px;
    width: 10px;
    height: 10px;
    background: #0000;    /* 元素本身透明 */
    border-radius: 50%;   /* 圓角產生圓形,影子才會是圓形 */
    /* 多重陰影 */
    box-shadow: 
      #f00 50px 0 0 0,
      #f00 46.19px 19.14px 0 0,
      #f00 35.36px 35.36px 0 0,
      #f00 19.14px 46.19px 0 0,
      #f00 0 50px 0 0,
      #f00 -19.14px 46.19px 0 0,
      #f00 -35.36px 35.36px 0 0,
      #f00 -46.19px 19.14px 0 0,
      #f00 -50px 0 0 0,
      #f00 -46.19px -19.14px 0 0,
      #f00 -35.36px -35.36px 0 0,
      #f00 -19.14px -46.19px 0 0,
      #f00 0 -50px 0 0,
      #f00 19.14px -46.19px 0 0,
      #f00 35.36px -35.36px 0 0,
      #f00 46.19px -19.14px 0 0;
  }
</style>

CSS 教學 - CSS 製作圓點載入動畫 ( 陰影動畫 ) - 多重陰影產生十六個圓點

使用 @property 和 animation 讓陰影動起來

如果要在 CSS 的陰影無法使用基本的方法套用動畫效果 ( 類似漸層色無法直接套用動畫效果 ),必須使用「自訂屬性 @property」,透過改變屬性值的方式產生動畫,下方範例會新增一個 --c 自訂屬性,並將陰影的「尺寸」換成 var(--c),透過改變自訂屬性的方式讓圓點出現和消失。

<!-- HTML 程式碼 -->
<div class="c"></div>

<!-- CSS 程式碼 -->
<style>
  @property --c {
    syntax: "<length>";  /* 自訂屬性類型是長度 */
    inherits: true;
    initial-value: -5px; /* 自訂屬性預設值為 -5px */
  }
  .c {
    position: absolute;
    width: 10px;
    height: 10px;
    background: #0000;
    border-radius: 50%;
    top: 100px;
    left: 100px;
    /* 陰影尺寸都改成 var(--c) 讀取自訂屬性 */
    box-shadow: 
      #f00 50px 0 0 var(--c),
      #f00 46.19px 19.14px 0 var(--c),
      #f00 35.36px 35.36px 0 var(--c),
      #f00 19.14px 46.19px 0 var(--c),
      #f00 0 50px 0 var(--c),
      #f00 -19.14px 46.19px 0 var(--c),
      #f00 -35.36px 35.36px 0 var(--c),
      #f00 -46.19px 19.14px 0 var(--c),
      #f00 -50px 0 0 var(--c),
      #f00 -46.19px -19.14px 0 var(--c),
      #f00 -35.36px -35.36px 0 var(--c),
      #f00 -19.14px -46.19px 0 var(--c),
      #f00 0 -50px 0 var(--c),
      #f00 19.14px -46.19px 0 var(--c),
      #f00 35.36px -35.36px 0 var(--c),
      #f00 46.19px -19.14px 0 var(--c);
    animation: oxxo 1s alternate infinite; /* 重複不斷播放 */
  }
  /* 動畫改變自訂屬性 */
  @keyframes oxxo {
    0% {--c: -5px;}  /* -5px 為圓點大小 10px 的半徑 */
    100% {--c: 0;}
  }
</style>

CSS 教學 - CSS 製作圓點載入動畫 ( 陰影動畫 ) - 使用 @property 和 animation 讓陰影動起來

使用動畫延遲,讓圓點依序出現

為了利用圓點「大小出現的時間差」產生「旋轉」效果,必須透過「動畫延遲」和「多重動畫」方式,讓每個圓點出現的時間有所不同並依序出現,修*改上述的範例程式碼,增加一些自訂屬性 ( 改成 --c1、--c2 等 ) 以及動畫影格名稱 ( oxxo1、oxxo2 等 ),並加入延遲時間,就能產生依序出現的效果,下方範例先修改四個圓點 ( 程式碼會開始大幅增加 )。

<!-- HTML 程式碼 -->
<div class="c"></div>

<!-- CSS 程式碼 -->
<style>
  /* 自訂屬性 */
  @property --c1 {
    syntax: "<length>";
    inherits: true;
    initial-value: -5px;
  }
  @property --c2 {
    syntax: "<length>";
    inherits: true;
    initial-value: -5px;
  }
  @property --c3 {
    syntax: "<length>";
    inherits: true;
    initial-value: -5px;
  }
  @property --c4 {
    syntax: "<length>";
    inherits: true;
    initial-value: -5px;
  }
  .c {
    position: absolute;
    width: 10px;
    height: 10px;
    background: #0000;
    border-radius: 50%;
    top: 100px;
    left: 100px;
    /* 注意自訂屬性名稱不同 */
    box-shadow: 
      #f00 50px 0 0 var(--c1),
      #f00 46.19px 19.14px 0 var(--c2),
      #f00 35.36px 35.36px 0 var(--c3),
      #f00 19.14px 46.19px 0 var(--c4),
      #f00 0 50px 0 var(--c1),
      #f00 -19.14px 46.19px 0 var(--c2),
      #f00 -35.36px 35.36px 0 var(--c3),
      #f00 -46.19px 19.14px 0 var(--c4),
      #f00 -50px 0 0 var(--c1),
      #f00 -46.19px -19.14px 0 var(--c2),
      #f00 -35.36px -35.36px 0 var(--c3),
      #f00 -19.14px -46.19px 0 var(--c4),
      #f00 0 -50px 0 var(--c1),
      #f00 19.14px -46.19px 0 var(--c2),
      #f00 35.36px -35.36px 0 var(--c3),
      #f00 46.19px -19.14px 0 var(--c4);
    /* 多重動畫,每個動畫都增加 0.2s 延遲 */
    animation: oxxo1 1s alternate infinite,
      oxxo2 1s 0.2s alternate infinite,
      oxxo3 1s 0.4s alternate infinite,
      oxxo4 1s 0.6s alternate infinite;
  }
  /* 動畫影格名稱不同 */
  @keyframes oxxo1 {
    0% {--c1: -5px;}
    100% {--c1: 0;}
  }
  @keyframes oxxo2 {
    0% {--c2: -5px;}
    100% {--c2: 0;}
  }
  @keyframes oxxo3 {
    0% {--c3: -5px;}
    100% {--c3: 0;}
  }
  @keyframes oxxo4 {
    0% {--c4: -5px;}
    100% {--c4: 0;}
  } 
</style>

CSS 教學 - CSS 製作圓點載入動畫 ( 陰影動畫 ) - 使用動畫延遲,讓圓點依序出現

圓點載入動畫 ( 使用 JavaScript 簡化程式碼 )

因為透過多重陰影產生的動畫需要撰寫「大量又類似」的 CSS 程式碼,為了縮減程式碼長度,可以透過 JavaScript 將重複的部分獨立出來,並運用迴圈替換變數,後續也比較方便修改調整,如果要做得更有彈性,連同陰影的顏色和陰影位置都能運用 JavaScript 來調整,詳細說明可以參考下方範例:

<!-- HTML 程式碼 -->
<div class="c"></div>

<!-- CSS 程式碼 -->
<style>
  /* 將重複的程式碼全部交由 JS 處裡 */
  .c {
    position: absolute;
    width: 10px;
    height: 10px;
    background: #0000;
    border-radius: 50%;
    top: 100px;
    left: 100px;
  }
</style>

<!-- JavaScript 程式碼 -->
<script>
  const head = document.head;   // 取得頁面的 head 區塊
  const style = document.createElement('style'); // 建立一個新的 style 區塊
  head.appendChild(style);      // head 區塊中加入 style

  let cssProperty = '';         // CSS 自訂屬性和影格內容
  let anime = '';               // CSS 動畫
  let boxShadow = '';           // CSS 陰影
  let color = 'red';            // 圓點顏色
  let radius = 50;              // 繞圓的半徑
  let num = 16;                 // 圓的數量
  let deg = ~~(360/num*10)/10;  // 根據數量計算角度,取值到小數點第二位
  let cr = 10;                  // 小圓點半徑

  // 建立函式,根據角度計算位置
  function pos(angle, r){
    let rad = angle*Math.PI/180; // 換算弧度
    let px = Math.cos(rad)*r;    // x 座標
    let py = Math.sin(rad)*r;    // y 座標
    return [px, py];             // 回傳陣列結果
  }

  // 使用迴圈,產生每個點的自訂屬性和動畫影格名稱
  for(let i=1; i<num+1; i++){
    let c = `
      @property --c${i} {
        syntax: "<length>";
        inherits: true;
        initial-value: -${cr}px;
      }
      @keyframes oxxo${i} {
        0% {--c${i}: -${cr}px;}
        100% {--c${i}: 0;}
      }`;
    let xy = pos((i-1)*deg, radius); // 透過函式取得 xy 座標
    let x = ~~(xy[0]*100)/100;       // x 座標,取值到小數點第二位
    let y = ~~(xy[1]*100)/100;       // y 座標,取值到小數點第二位
    let sec = ~~((i-1)*0.2*10)/10;   // 延遲秒數,取值到小數點第一位,處理 JS 很多的小數點問題
    anime = anime + `oxxo${i} 1s ${sec}s alternate infinite,`;        // 動畫 CSS
    boxShadow = boxShadow + `${color} ${x}px ${y}px 0 var(--c${i}),`; // 陰影 CSS
    cssProperty = cssProperty + c;   // 組合 CSS
  }
  anime = anime.replace(/.$/,';');           // 替換最後的 , 為 ;
  boxShadow = boxShadow.replace(/.$/,';');   // 替換最後的 , 為 ;
  cssProperty = cssProperty + `.c {animation: ${anime} box-shadow: ${boxShadow} }`; // 組合 CSS
  style.appendChild(document.createTextNode(cssProperty)); // 添加 CSS
</script>

CSS 教學 - CSS 製作圓點載入動畫 ( 陰影動畫 ) - 圓點載入動畫 ( 使用 JavaScript 簡化程式碼 )

CSS 教學 - CSS 製作圓點載入動畫 ( 陰影動畫 ) - 圓點載入動畫 ( 使用 JavaScript 簡化程式碼 )

小結

CSS 的圓點載入動畫其實不複雜,只是程式碼多了點 ( 大多都是重複撰寫 ),單純透過 CSS 也可以實現,只是為了減少重複的程式碼,使用 JavaScript 處理會更有效率,不過這篇範例的重點是在於多重陰影、多重動畫、自訂屬性的互相搭配,只要熟練運用,就能做出許多有趣的效果。


上一篇
( Day 19 ) 純 CSS 水波效果 ( 最後有點不純 )
下一篇
( Day 21 ) 純 CSS 字母翻牌效果
系列文
關於那些有趣的 CSS 效果35
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言