iT邦幫忙

2025 iThome 鐵人賽

DAY 22
2
Modern Web

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

( Day 22 ) 純也不純的 CSS 探照燈動畫 ( CSS Spotlight )

  • 分享至 

  • xImage
  •  

今天去逛了華山的哆啦 A 夢特展,裡面有個動畫效果是哆啦 A 夢在昏暗的房間裡用縮小燈照了哆啦 B 夢 ( 哆啦美 ) 和大雄,所以我就決定也來做個純 CSS 的探照燈動畫,雖然是很久以前做的,跟哆啦 A 夢特展沒有什麼關聯性就是了... 至於為什麼說純也不純呢?因為 CSS 雖然能夠做出探照燈,但只能做出動畫效果,沒辦法讓探照燈跟著滑鼠移動,如果要跟著滑鼠移動,還是得透過 JavaScript 來輔助囉~

純也不純的 CSS 探照燈動畫 ( CSS Spotlight )

正文開始

這篇教學會使用 CSS 的裁切路徑 clip-path 和影像遮罩 mask,將虛擬元素轉換成「探照燈」,做出有趣又吸睛的 CSS 探照燈動畫,最後還會搭配 JavaScript 讓探照燈可以跟隨滑鼠移動。

CSS 教學 - CSS 探照燈動畫 ( CSS Spotlight )

探照燈動畫 ( 虛擬元素 + 裁切路徑 clip-path )

製作探照燈的第一種方法為「虛擬元素 + 裁切路徑」,透過 clip-path 樣式屬性,將蓋在背景圖上的虛擬元素 ::before 裁切出一個圓形,搭配半透明的黑色 ::after,就能做出探照燈,最後只要搭配動畫,就能讓探照燈動起來,詳細說明寫在下方範例註解中。

<!-- HTML 程式碼 -->
<div></div>

<!-- CSS 程式碼 -->
<style>
  div {
    position: relative;       /* 讓虛擬元素定位參考 */
    width: 450px;
    height: 300px;
    background: url("https://steam.oxxostudio.tw/image/index-css.jpg");
    background-size: contain; /* 背景填滿設定 */
  }
  div::before, div::after {
    position: absolute;       /* 絕對定位產生重疊 */
    white-space: pre;         /* 讓 content 支援換行符 */
    content: "Hello World\A\A\A oxxo.studio"; /* 加入文字 */
    line-height: 1.5;
    width: 100%;              /* 尺寸與底圖大小相同 */
    height: 100%;
    text-align: center;
    font-size: 50px;
  }
  div::before {  
    color: #fff3;             /* 文字較暗,像是被遮住 */ 
    background: #000c;        /* 半透明黑色遮住底圖 */
  }
  div::after {
    color: #fff;              /* 文字較亮,像是被燈照到 */ 
    background: url("https://steam.oxxostudio.tw/image/index-css.jpg"); /* 和底圖相同的圖 */
    background-size: contain; /* 和底圖相同的填滿設定 */
    clip-path: circle(120px at 50% 50%); /* 使用圓形裁切路徑 */ 
    animation: oxxo 3s alternate infinite ease-in-out;
  }
  @keyframes oxxo {
    0% {clip-path: circle(120px at 10% 50%);}   /* 動畫改變圓心位置 */
    100% {clip-path: circle(120px at 90% 50%);}
  }
</style>

CSS 教學 - CSS 探照燈動畫 ( CSS Spotlight ) - CSS 探照燈動畫 ( 虛擬元素 + 裁切路徑 clip-path )

探照燈動畫 ( 虛擬元素 + 影像遮罩 mask )

製作探照燈的第二種方法為「虛擬元素 + 影像遮罩」,透過 mask-image 樣式屬性讀取圓形漸層 radial-gradient,將蓋在背景圖上黑色半透明的虛擬元素 ::before 裁切出一個圓形,就能做出探照燈,最後只要搭配動畫,就能讓探照燈動起來,詳細說明寫在下方範例註解中。

<!-- HTML 程式碼 -->
<div>
  <h1>Hello World</h1>
  <h2>oxxo.studio</h2>
</div>

<!-- CSS 程式碼 -->
<style>
  /* 百分比自訂屬性 */
  @property --x {
    syntax: "<percentage>";
    inherits: true;
    initial-value: 10%;
  }
  /* 百分比自訂屬性 */
  @property --y {
    syntax: "<percentage>";
    inherits: true;
    initial-value: 50%;
  }
  /* 放在探照燈效果中的內容 */
  h1, h2 {
    text-align: center;
    margin: 0;
    padding: 0;
    font-size: 50px;
    line-height: 1;
  }
  h2 {margin-top: 160px;}
  div {
    position: relative; /* 提供虛擬元素定位參考 */
    width: 450px;
    height: 300px;
    background: url("https://steam.oxxostudio.tw/image/index-css.jpg");
    background-size: contain;
    box-sizing: border-box; /* 寬度包含 padding */
    padding: 20px;
    color: #fff;
  }
  div::before {
    position: absolute;  /* 絕對定位覆蓋底圖 */
    content: "";
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: #000c;     /* 半透明黑色 */
    mask-mode: luminance;  /* 設定遮罩圖片為亮度模式 */
    mask-image: radial-gradient(circle at var(--x) var(--y), #000 120px, #fff 120px); /* 遮罩效果 */
    animation: oxxo 3s alternate infinite ease-in-out;
  }
  @keyframes oxxo {
    0% {--x: 10%;}     /* 動畫改變圓心位置 */
    100% {--x: 90%;}
  }
</style>

CSS 教學 - CSS 探照燈動畫 ( CSS Spotlight ) - CSS 探照燈動畫 ( 虛擬元素 + 影像遮罩 mask )

JavaScript 滑鼠控制探照燈 ( 裁切版 )

延伸上述「虛擬元素 + 裁切路徑 clip-path」範例程式碼,先將 CSS 中圓心位置改用「CSS 變數」,接著就能透過 JavaScript 把滑鼠座標的值賦予給 CSS 變數,探照燈也就會跟著滑鼠移動,詳細說明參考下方範例註解。

<!-- HTML 程式碼 -->
<div></div>

<!-- CSS 程式碼 -->
<style>
  div {
    position: relative;
    width: 450px;
    height: 300px;
    background: url("https://steam.oxxostudio.tw/image/index-css.jpg");
    background-size: contain;
    box-sizing: border-box;
    --x: 50%;
    --y: 50%;
  }
  div::before, div::after {
    box-sizing: border-box;
    position: absolute;
    white-space: pre;
    content: "Hello World\A\A\A oxxo.studio";
    line-height: 1.5;
    width: 100%;
    height: 100%;
    text-align: center;
    font-size: 50px;
  }
  div::before {
    color: #fff3;
    background: #000c;
  }
  div::after {
    color: #fff;
    background: url("https://steam.oxxostudio.tw/image/index-css.jpg");
    background-size: contain;
    clip-path: circle(120px at var(--x) var(--y));
    animation: oxxo 3s alternate infinite ease-in-out;
  }
</style>

<script>
  const item = document.querySelector('div');
  let ox = item.offsetLeft;    // 取得這個元素的座標,方便轉換為遮罩相對位置
  let oy = item.offsetTop;
  item.addEventListener('mousemove', function(e){
    let x = e.pageX - ox;      // 計算滑鼠與座標的相對位置,也就是實際點擊圖片的位置
    let y = e.pageY - oy;      // 計算滑鼠與座標的相對位置,也就是實際點擊圖片的位置
    item.style.setProperty('--x',`${x}px`); // 替換 CSS 變數內容
    item.style.setProperty('--y',`${y}px`); // 替換 CSS 變數內容
  });
</script>

CSS 教學 - CSS 探照燈動畫 ( CSS Spotlight ) - JavaScript 滑鼠控制 CSS 探照燈 ( 裁切版 )

JavaScript 滑鼠控制探照燈 ( 遮罩版 ) {a4}

延伸上述「虛擬元素 + 影像遮罩 mask」範例程式碼,因為已經使用 CSS 自訂屬性作圓心位置,可以直接裡用 JavaScript 把滑鼠座標的值賦予給 CSS 屬性,探照燈也就會跟著滑鼠移動,詳細說明參考下方範例註解。

<!-- HTML 程式碼 -->
<div>
  <h1>Hello World</h1>
  <h2>oxxo.studio</h2>
</div>

<!-- CSS 程式碼 -->
<style>
  /* 長度自訂屬性 */
  @property --x {
    syntax: "<length>";
    inherits: true;
    initial-value: 0px;
  }
  /* 長度比自訂屬性 */
  @property --y {
    syntax: "<length>";
    inherits: true;
    initial-value: 0px;
  }
  h1, h2 {
    text-align: center;
    margin: 0;
    padding: 0;
    font-size: 50px;
    line-height: 1;
  }
  h2 {margin-top: 160px;}
  div {
    position: relative;
    width: 450px;
    height: 300px;
    background: url("https://steam.oxxostudio.tw/image/index-css.jpg");
    background-size: contain;
    box-sizing: border-box;
    padding: 20px;
    color: #fff;
  }
  div::before {
    position: absolute;
    content: "";
    top: 0;
    left: 0;
    background: #000c;
    width: 100%;
    height: 100%;
    mask-mode: luminance;  /* 設定遮罩圖片為亮度模式 */
    mask-image: radial-gradient(circle at var(--x) var(--y), #000 120px, #fff 120px);
  }
</style>

<script>
  const item = document.querySelector('div');
  let ox = item.offsetLeft;    // 取得這個元素的座標,方便轉換為遮罩相對位置
  let oy = item.offsetTop;
  item.addEventListener('mousemove', function(e){
    let x = e.pageX - ox;      // 計算滑鼠與座標的相對位置,也就是實際點擊圖片的位置
    let y = e.pageY - oy;      // 計算滑鼠與座標的相對位置,也就是實際點擊圖片的位置
    item.style.setProperty('--x',`${x}px`); // 替換 CSS 屬性內容
    item.style.setProperty('--y',`${y}px`); // 替換 CSS 屬性內容
  });
</script>

CSS 教學 - CSS 探照燈動畫 ( CSS Spotlight ) - JavaScript 滑鼠控制 CSS 探照燈 ( 遮罩版 )

小結

這篇教學介紹了兩種製作遮罩的方法,不外乎都是需要將黑色或圖形裁切成圓形,相信只要運用得當,一定能在網站中產生有趣又吸睛的效果喔。


上一篇
( Day 21 ) 純 CSS 字母翻牌效果
下一篇
( Day 23 ) 純 CSS 流動色彩文字
系列文
關於那些有趣的 CSS 效果35
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言