[JavaScript 30]Day16-CSS Text Shadow Mouse Move Effect
今天要練習如何偵測到滑鼠移動位置,進而利用 JS 動態改變 CSS 樣式,製作出「隨著滑鼠移動,會變換位置的陰影效果」。
鼠標移動至 <h1>
字樣中心 :
鼠標在 <h1>
字樣周圍移動,不同顏色的陰影樣式,位置會跟著產生變化 :
學習重點
- 監聽 mousemove 事件
- ES6 解構賦值
offsetWidth
、offsetHeight
: 元素寬、高offsetLeft
、offsetTop
: 元素左邊、上面與 offsetParent 的距離e.offsetX
、e.offsetY
: 滑鼠距離元素左上角的 X、Y 軸距離Math.round()
: 回傳四捨五入後的近似值
觀察範例檔案初始狀態
HTML
html 有個簡單的結構 ,.hero
裡包著一個 <h1>
<div class="hero">
<h1 contenteditable>🔥WOAH!</h1>
</div>
CSS
- 根據 CSS 設定,
.hero
是佔滿整個瀏覽器視窗範圍的狀態。 - 範例預先在 h1 加上了一個 text-shadow 樣式,可能是方便讓我們了解設定方法。之後用 JS 加上其他陰影效果後,可以將原先在 CSS 內的這段 text-shadow 設定刪除。
.hero { min-height: 100vh; display: flex; justify-content: center; align-items: center; color: black;}h1 { text-shadow: 10px 10px 0 rgba(0,0,0,1); font-size: 100px;}
(最後完成的完整 JS 程式碼,以及檔案下載、課程連結,將放在最下方)
步驟拆解
一、對 .hero
監聽 mousemove 事件
二、取得 .hero
在視窗上的寬高範圍,以及動態滑鼠座標
三、整合鼠標進入<h1>
範圍內的座標
四、將滑鼠座標數值,轉換為想設定的樣式 px 範圍
五、調整陰影位置
六、加入多種顏色、不同位置的陰影樣式
一、對 .hero
監聽 mousemove 事件
二、取得 .hero 在視窗上的寬高範圍,以及動態滑鼠座標
[小補充] ES6 解構賦值寫法 :
const width = hero.offsetWidth;
const height = hero.offsetHeight;
// 可簡寫成
const { offsetWidth: width, offsetHeight: height} = hero;
===
let x = e.offsetX;
let y = e.offsetY;// 可簡寫成
let { offestX: x, offsetY: y } = e;
三、整合鼠標進入 <h1> 範圍內的座標
當我們用 console.log(x, y)
組成座標,觀察滑鼠座標的變化,會發現當鼠標移動進 <h1>
範圍內的左上角,座標又會從(0 , 0) 開始變化。
問題 :
雖然我們是對 .hero
監聽 mousemove 事件,但 .hero
裡面有包裹一個子層,也就 <h1>
,當滑鼠移動到 <h1>
範圍內,e.target
將會改變為子層的 <h1>
,回傳的 e.offsetX
、e.offsetY
,也會變成在 <h1>
範圍內的座標。
解決方法:
為了防止鼠標進入 <h1>
範圍後,變成以<h1>
範圍為基準的相對座標,我們可以想辦法偵測當鼠標進入 <h1>
範圍後,就將 <h1>
距離視窗左邊的寬度,以及距離上方的高度,補進座標數值內。如此一來,我們抓到的座標就得以連貫。
如何判斷鼠標進入到 <h1>
範圍內了?
因為我們是對 .hero
監聽 mousemove 事件,所以 shadow()
函式內的 this
會指向 .hero
。
但 e.target
會隨著鼠標移動至 .hero
或 <h1>
的範圍,而有所改變。
所以我們可以用 if(this !== e.target) {}
來判斷,當 e.target
不等於 .hero
,就表示此時鼠標已經移進 <h1>
的範圍內。
四、將滑鼠座標數值,轉換為想設定的樣式 px 範圍
1. 宣告 walk 變數,設定範圍
我們希望陰影樣式的位置,變化範圍在 100 px 內
const walk = 100;
2. 計算陰影位置座標數值
- xWalk 計算原理 :
將x / width
,可以得到「目前 x 座標數值」佔「.hero
寬度範圍」的百分比,再將它乘上 walk,即可算出滑鼠移動到任意 x 座標時,陰影樣式會變化到距離原字樣多少 px 的位置。
再使用Math.round()
取得四捨五入後的整數。 - yWalk 計算原理與 xWalk 相似。
const xWalk = Math.round((x / width * walk));const yWalk = Math.round((y / height * walk));
3. 為 <h1>
加上 CSS 陰影樣式
帶入剛剛計算的 xWalk、yWalk,作為陰影樣式的前兩個設定值。
隨著鼠標移動,xWalk、yWalk 數值也會變化,進而造成陰影位置變化,形成動態效果。
text.style.textShadow = `${xWalk}px ${yWalk}px 0 red`;
五、調整陰影位置
問題 :
此時的紅色陰影樣式,雖然會隨著鼠標變換位置,但效果並非我們所預期。
鼠標移至視窗右下角 :
鼠標移至視窗左上角 :
希望紅色陰影在黑字樣的左上方,但呈現的效果卻是與黑字重疊
因為我們目前的設定,會讓陰影位置的數值變化如下 :
鼠標移至右下角 => 陰影 CSS : text-shadow: 100px 100px 0px red;
鼠標移至左上角 => 陰影 CSS : text-shadow: 0px 0px 0px red;
而我們想要的效果,應該要以 <h1>
字樣中心為基準點,去做相對位置數值的變化
鼠標移至右下角 => 陰影 CSS : text-shadow: 50px 50px 0px red;
鼠標移至左上角 => 陰影 CSS : text-shadow: -50px -50px 0px red;
解決方法 :
在 xWalk、yWalk 的計算式,分別都再減去二分之一的 walk 值 :
如此一來,陰影位置,就可以以 <h1>
字樣中心點去做變化。
鼠標移至視窗左上角,陰影位置能成功往左上方移動 :
六、加入多種顏色、不同位置的陰影樣式
text-shadow 可設定多層的陰影,將每層陰影設定不同顏色,並在 x、y 軸數值上做一點小變化,讓不同顏色的陰影朝不同方向、位置做變化。
text.style.textShadow = ` ${xWalk}px ${yWalk}px 0 rgba(255,0,255,0.7), ${xWalk * -1}px ${yWalk}px 0 rgba(0,255,255,0.7), ${yWalk}px ${xWalk * -1}px 0 rgba(0,255,0,0.7), ${yWalk * -1}px ${xWalk}px 0 rgba(0,0,255,0.7)`;
就能完成今天範例的效果 :
也可以玩玩不同陰影樣式,例如讓它呈現霓虹燈光暈的效果,並隨著鼠標往不同方向移動 :
text.style.textShadow = ` ${xWalk}px ${yWalk}px 5px white, ${xWalk}px ${yWalk}px 10px white, ${xWalk}px ${yWalk}px 15px white, ${xWalk}px ${yWalk}px 40px #ff6723, ${xWalk}px ${yWalk}px 70px #ff6723`;
今天的練習就到這邊結束囉~
完整 JS 程式碼
const hero = document.querySelector('.hero');
const text = hero.querySelector('h1');
const walk = 500; // 500pxfunction shadow(e) {
const { offsetWidth: width, offsetHeight: height } = hero;
let { offsetX: x, offsetY: y } = e;
if (this !== e.target) {
x = x + e.target.offsetLeft;
y = y + e.target.offsetTop;
}
const xWalk = Math.round((x / width * walk) - (walk / 2));
const yWalk = Math.round((y / height * walk) - (walk / 2));
text.style.textShadow = `
${xWalk}px ${yWalk}px 0 rgba(255,0,255,0.7),
${xWalk * -1}px ${yWalk}px 0 rgba(0,255,255,0.7),
${yWalk}px ${xWalk * -1}px 0 rgba(0,255,0,0.7),
${yWalk * -1}px ${xWalk}px 0 rgba(0,0,255,0.7)
`;
}
hero.addEventListener('mousemove', shadow);
參考資料
範例檔案下載 :
JavaScript 30 課程註冊連結(輸入 email 免費註冊) :