CSS 料理室 – CSS 變數辛香料:不用 Sass、不用 JavaScript,也能實做 Dark Mode Theme 切換!

02/26/2022 ・ 技術分享

👩‍🍳 關於 CSS 料理室 :

CSS 料理室的主廚可能會打翻麵粉、可能會調配出黑暗料理,但是實驗精神是不會少的!

總之,讓我們一起透過一道又一道料理,認識 CSS 吧!

 

🍽 食譜完成照:

 

🥬 食材準備:

  1. CSS 變數: -*
  2. HTML input 標籤: input[type="checkbox"]
  3. CSS 選取器: X + YX ~ Y

 

📒 食譜簡介:

這次製作的料理,主要是使用原生的 CSS 變數 實做出深色模式和淺色模式的切換。除此之外,我們還會利用 HTML <input> 標籤當中的 checkbox 實做 『切換』這個動作,以下將介紹這些食材的特性。

 

🍖 食材介紹(ㄧ): CSS 自訂變數 (--*)

CSS 變數 (--*) 讓我們自訂命名,讓規範或常用的數值取一個名字,好讓其他成員在使用時可以更好理解。 例如:


/* 原本的樣式 */
.card {
  background: #FFFFFF;
  color: rgba(255, 98, 98, 1);
}

/* 使用自訂變數 */
:root {
  --bg-white: #FFFFFF;
  --text-pink: #FF6262;
}

/* 套上變數 */
.card {
  background: var(--bg-white);
  color: var(--text-pink);
}

從上面使用自訂變數的範例中,可以很快速的知道 .card 使用了 白色 的背景, 粉紅色的文字 樣式。如果我們想要改粉紅色的色票,只要到 --text-pink 中去調整就行了!

 

全域 CSS 變數與獨立區域的 CSS 變數

在使用 CSS 變數時,也可以將這個變數選擇放在全域或是某個區域範圍內,在 :root {....} 當中的變數是全域共用的:


/* :root 全域共用的樣式 */
:root {
  --pink: #FF6262;
}

/* 只有在 .container 裡面的 --pink */
.container {
  --pink: #FF006B;
}

.container {
  color: var(--pink);   /* pink => #FF006B */
}

body {
  color: var(--pink);  /* pink => #FF6262 */
}

 

🍖 食材介紹(二): <input type="checkbox">

<input type="checkbox"> 是一個單純的勾選標籤,有三種狀態:

並且在 CSS 也可以直接設定這些狀態樣式,例如:


input[type="checkbox"] {
  /* 這邊設定的 Unchecked 的樣式 */
}

input[type="checkbox"]:checked {
  /* 這邊設定的 checked 的樣式 */
}

input[type="checkbox"]:indeterminate {
  /* 這邊設定的 indeterminate 的樣式 */
}

其中 indeterminate 這個介於已選取和未選取之間的狀態,是需要透過 JavaScript 去定義在什麼情況下會出現 indeterminate 狀態。這次不會使用這個狀態。

我們可以利用 checkbox 的兩個狀態 : unchecked & checked 去做到類似 JavaScript『點擊』後觸發的樣式。

 

🍖 食材介紹(三): CSS 選取器 X + Y , X ~ Y

最後一個重要食材 – CSS 選取器,從上面兩個食材當中我們已經準備好:

  1. 將樣式顏色命名:管理 CSS 自訂變數
  2. 如何觸發樣式:使用 <input type=checkbox>

接著,我們需要指定樣式『套用的範圍』。 從完成照當中仔細地看到,我是將滑鼠進入 Dark / Light 的按鈕時才會觸發,實際上 HTML 的結構層,我是將卡片和按鈕排在同一層,讓觸發範圍限制在按鈕樣式 <input> 裡。如果我將卡片樣式放進去 <input> 裡,那麼整張卡片將會一起被當成觸發範圍。

如果我的 input 和卡片樣式是同層的話,我可以透過 X ~ Y 來選取:

 

CSS 選取器: X ~ Y

選取同層(兄弟層)的元素,意思是選取在 X 之後的 Y

 

CSS 選取器:X + Y

選取緊鄰同層元素,參考以下範例,他只會選取到緊鄰<h1> 的 <p>

 

👩‍🍳 料理步驟: 實現 CSS 變數 Dark Mode 吧!

🖋 步驟一:使用 CSS 自訂變數,建立色票

首先,先將深色和淺色模式會使用到的顏色都先運用自訂變數,建立色票,準備好:


:root {
  --bg-color: #F1E8E8;
  --white: #FFFFFF;
  --black: #282F3C;
  --pink: rgba(255, 98, 98, 1);
  --pink-light: rgba(255, 98, 98, 0.3);
  --pink-lighter: rgba(255, 98, 98, 0.1);
  --gray: #959595;
}

 

🖋 步驟二:設定 Checkbox 樣式

<div class="container">
  <input type="check" type="checkbox" id="toggle" name="toggletheme">
     <label for="toggle">
        <span class="dark">Dark</span>
        <span class="light">Light</span>
     </label>
  </input>
</div>

 

1. <label> 標籤的 for 屬性:

在示範上將 <label> 存取文字,並且放在與 <input> 同層的位置,我們可以指定這兩者產生關聯,讓 <input> 觸發的條件對應到 <label> 內。如何設置呢? 將 <input> 的 id 與 <label> 的 for 設置成相同值:

 

2. 選取 <input> 緊鄰的 <label>

首先我們將瀏覽預設的 <input> 樣式隱藏,並透過 <label> 建立這個按鈕的樣式。 我使用 X + Y 從 <input> 狀態控制 <label> 樣式,實際上操作會像這樣:


/* 隱藏預設 input 樣式 */
input[type="checkbox"] {
  display: none;
}

/* input[type="checkbox"] 緊鄰的 label */
/* 在 checkbox 未點擊的樣式 */
input[type="checkbox"] + label {
    ......
}

/* 在 checkbox 點擊後的樣式 */
input[type="checkbox"]:checked + label {
    .....
}

Tip: 可以看到 label 裡面有 <span>Dark</span> 和 <span>Light</span> 這會用 checked 判斷在 Light 模式時,<span>Light</span> 的文字隱藏,Dark 模式則是相反。

 

3. ::before 圓形樣式:

另外使用 ::before 做出假圓形,模擬出按鈕樣式:

從上面的 Toggle 按鈕當中可以看到,我已經選取到 :checked的狀態時,按鈕會是如何呈現的,如此就能夠延伸出在 :checked狀態下的 .card的樣式。

 

🖋 步驟三:刻出卡片

從上一步,我們建立了切換深淺色的按鈕後,接著我們就可以利用:

 

使用 CSS 選取器 X ~ Y 製作卡片樣式。

首先 input 、 label 和製作卡片的樣式 <div class="card"></div> 放在同層,像以下:

<div class="container">
  <!-- 按鈕 -->
  <input type="checkbox" id="toggle" name="toggletheme"></input>
  <label for="toggle"></label>

   <!-- 卡片樣式 --> 
   <div class="card"> 
    ...... 
   </div>
</div>

可以從上面看到,要使用 <input> 的 :checked 選取器來製作點擊後的卡片樣式,中間隔了 <label> 要怎麼樣能夠跨過 <label> 呢?

這時候就可以使用 CSS 選取器:X ~ Y ! 直接選取在 <input> 之後的 <div class="card">

因此我們就能夠這樣做設定:


/* 預設卡片樣式 (未點擊的狀態) */
.card {
    ...
}

/* 點擊後的卡片樣式 (Dark Mode) */
input[type="checkbox"]:checked ~ .card {
    ...
}

 

🎁 Bonus – CSS 選取器:X > Y

從完成的 Card 樣式,可以看到我使用大量的 X > Y 方式選取,這個選取器的特性是什麼呢?

X > Y 是選取緊鄰子層元素,這邊則是選取相連同層的元素,讓我們看以下範例:

結語

以上就是這次的 CSS 料理室 – CSS 變數辛香料,看完你是否也想嘗試玩玩看 Dark Mode 切換了嗎?

雖然對於 CSS 變數命名還是覺得有點長(囉唆?XD )

但,看到 CSS 解決了變數的方法,真覺得是一大福音啊!

除此之外 CSS 的 :checked 也是一個很有趣的的選取器,實務上也經常使用這樣的選取器製作像是收合樣式、開啟關閉的樣式,

更多的方法也可以參閱:You Don’t Need JavaScript | Accordion