iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 3
0

任務內容

這章的目的是學會如何宣告CSS變數, 在CSS內呼叫CSS變數, 以及用JS控制CSS變數.
下面有三條input range可以調整, 我們希望拖動spacing的range能夠改變畫面的padding大小, 拖動base可以同時改變標題中JS的字體顏色以及網頁的背景顏色, 拖動blur可以改變下方圖片的模糊度... 衝了!

<h2>Update CSS Variables with <span class='hl'>JS</span></h2>

<div class="controls">
  <label for="spacing">Spacing:</label>
  <input id="spacing" type="range" name="spacing" min="10" max="200" value="10" data-sizing="px">

  <label for="blur">Blur:</label>
  <input id="blur" type="range" name="blur" min="0" max="25" value="10" data-sizing="px">

  <label for="base">Base Color</label>
  <input id="base" type="color" name="base" value="#ffc600">
</div>

<img src="https://source.unsplash.com/7bwQXzbF6KE/800x500">

作法

CSS變數的好處就是可以集中管理和重複使用! 透過實作讓字體和背景同時變色, 可以體悟到這點.

首先宣告CSS變數, CSS變數可以宣告在任何CSS Selector的範圍內, 宣告方式為--變數名稱: 變數值;.

要使用宣告的變數, 用 var 函數將變數名稱包著, 像這樣 var(--base).
下面CSS樣式, .hlcolorimgbackground值都使用了宣告的變數--base, 所以都會有#ffc600這個顏色, 如果--base儲存的顏色值被改變了, 標題的字體顏色和圖像的背景色都會跟著改變, 算是完成了第一步!

:root {
  --base: #ffc600;
}

.hl {
  color: var(--base);
}

img {
  background: var(--base);
}

宣告及使用CSS變數, 和宣告及使用JS變數一樣, 是有作用範圍(scope)的.

若將變數宣告在某個元素的CSS內, 只有該元素本身以及該元素的子元素, 孫元素, 子子孫孫們能夠使用該變數.

有些人會將變數直接宣告在:root這個虛擬類別(pseudo-class), 這個虛擬類別代表DOM的根, 也就是<html>的CSS Selector, 由於它是整顆DOM的最高點, 也就是眾元素們的祖靈, 因此大家都可以輕易地使用掛在上面的CSS變數.

imgpadding, filter也用CSS變數串好, 像這樣.

:root {
  --base: #ffc600;
  --spacing: 10px;
  --blur: 10px;
}

img {
  padding: var(--spacing);
  background: var(--base);
  filter: blur(var(--blur));
}

.hl {
  color: var(--base);
}

CSS Filter

filter: blur(10px)是CSS的濾鏡屬性, 可以讓被附加此屬性的元素有圖層濾鏡的效果, 像在網頁上用PS一樣. blur是模糊濾鏡, 只是其中一種, 還有像contrast反差, grayscale灰階等的可以選.

接下來要讓input元素的調整range和CSS變數勾搭了. 藉此實踐拖曳range能夠同時改變圖片背景色和標題字體色的效果.
程式碼如下:

const inputs = document.querySelectorAll('.controls input');

inputs.forEach(input => input.addEventListener('change', handleUpdate));
inputs.forEach(input => input.addEventListener('mousemove', handleUpdate));

先選取全部的<input>元素, 存到變數inputs裡面.
inputs清單裡面存的每個<input>元素都增設監聽器, 只要值有change或是有滑鼠在上面mousemove, 就用自訂的回呼函數handleUpdate更新變動.
自訂函數要執行下列步驟:

  1. 找到該input要控制的CSS變數
  2. 將CSS變數的值更動成對應的<input>目前的值.

程式碼大致如下:

function handleUpdate() {
  const suffix = this.dataset.sizing || '';
  document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
}

首先看到裡面用了很多this, 這裡的this會指向呼叫該函式的對象. 因為我們用forEach分別為每個<input>都設置了監聽器和回呼函式handleUpdate, 因此函式內的this會依照呼喚它的元素, 分別指向<input id="spacing">, <input id="blur">, <input id="base">. 藉此得以取用該元素的屬性.

suffix變數用來裝變數會用到的單位, 若遇到不需要CSS單位的變數, 就指定空值.

接著存取根元素內的變數, 改成對應<input>目前指到的值, 後面加上單位.
document.documentElement為根元素<html>, style.setProperty用來設定CSS某個屬性. this指到呼叫handleUpdate的該<input>.

整段跑起來像這樣:
<input id="spacing>的調整鈕被移動了! 裡面存的值從20變成40.
此時change事件被觸發了! handleUpdate函式執行!
<input id="spacing">data-sizing="px", "px"單位被存到變數suffix裡面
<input id=spacing">具有事先設好的屬性name="base"
因為調整鈕被移動, 現在屬性value="40"
:root內的CSS變數--base的值被改成40px.

希望這樣有比較清楚!

最後說一下為什麼要同時附加changemousemove的事件監聽器, 因為如果只有change監聽器, 是監聽<input>存的值被改變的瞬間觸發事件, 而值是在滑鼠放開的瞬間才會改變, 拖曳並不會放開滑鼠, 如果希望拖曳時值就要跟著改變, 就要多靠一個mousemove.

以上就是JS30 第三篇心得!

Reference

:root
CSS Filter
完整的練習程式碼


上一篇
Day 2 - JS & CSS Clock
下一篇
Day 4 - Array Cardio Part I
系列文
JS30 錄30

尚未有邦友留言

立即登入留言