# 層疊、繼承、權重與選擇器

### 級聯

CSS 的 C 就是代表著層疊 Cascade 的意思，可以把它想成等級的概念，如下範例：

```css
/* 等級 1 */
h1 {
    color: red;
}

/* 等級 2 */
h1 span {
    color: green;
}

/* 等級 3 */
h1 span span{
    color: yellow;
}
```

在之後的選擇器我們會再更近一步的說明，目前只要知道層疊的意義即可，而近期新推出的層疊階層 Cascade Layer 是更進階的技術，在章節五的管理裡會再介紹。

{% hint style="info" %}
我們即將進入 CSS 的核心概念，從這裡開始該打起精神學習囉！
{% endhint %}

在相同級聯、相同權重的情況下，最後定義的會是最終樣式，如下範例：

```css
/* 這個範例的結果，會是套用綠色文字。 */

h1 {
    color: red;
}

h1 {
    color: green;
}

```

### 繼承

Inheritance，就有如字面意思，直接將父母親層級的樣式沿用，即稱為繼承，如下範例：

{% embed url="<https://codepen.io/neillin1023/pen/ExRvxBg>" %}

在這個範例中，\<body> 已經有設定文字為藍色，所以他的子元素們都會繼承他的文字顏色，直到 \<span> 又再次設定文字顏色為黑色。

{% hint style="info" %}
注意，CSS 屬性有些會繼承，有些不會繼承，例如寬度。\
您可以在查詢屬性時，查看他的繼承欄位，例如 [MDN 的 color 屬性介紹頁](https://developer.mozilla.org/en-US/docs/Web/CSS/color#formal_definition)的定義區塊就有明確列出這個屬性是否可以繼承。
{% endhint %}

### 選擇器

<figure><img src="https://www.w3schools.com/css/img_selector.gif" alt=""><figcaption><p><a href="https://www.w3schools.com/css/css_syntax.asp">https://www.w3schools.com/css/css_syntax.asp</a></p></figcaption></figure>

其實我們已經使用過選擇器了，在這個篇幅我們會更近一步的學習更多的選擇器用法。

所謂的 CSS 選擇器，就是在 CSS 檔案內撰寫我們要「指定某個對象」樣式的這件事情，例如：

```html
<main>
    <p>
        <h1 id="main-title" class="main-title2" title="main-title3">這是標題</h1>
    </p>
</main>
```

如果我們要對 \<h1> 做樣式的話，我們至少有以下這些樣式可以執行：

<pre class="language-css"><code class="lang-css">/* 標籤選擇器 */
h1 {
    color: red;
}

/* 層疊選擇器，權重較高，層疊越多越耗效能 */
main p h1 {
    color: red;
}

/* id 選擇器 */
#main-title {
    color: red;
}

/* class 選擇器 */
.main-title2 {
    color: red;
}

/* 屬性選擇器 */
[title="main-title3"] {
    color: red;
}

/* 偽元素，常見為 :before 與 :after */
h1:before {
<strong>    content: '在「這是標題」前插入文字';
</strong>    color: red;
}

/*
偽類，又分為動態、結構、迴圈、表單 4 類
此範例為當滑鼠滑在 h1 上時，改變 h1 顏色。
*/
h1:hover {
    color: red;
}


/* 您也可以混合使用 */
#main-title.main-title2 {
    color: red;
}
</code></pre>

{% hint style="danger" %}
id 與 class 不能以數字開頭命名！

也不可以全部都是數字！
{% endhint %}

在多個標籤與混合使用的範例，您會發現前者有空格，後者無空格，這是 CSS 的定義，說明如下：

<pre class="language-css"><code class="lang-css">/* 有空格：代表選擇其子元素，例如在此範例中，p 是 main 的子元素，h1 是 main 和 p 的子元素 */
<strong>main p h1 {
</strong>    color: red;
}

/*
無空格：會使用在 id、class、屬性，通常用來選擇相同元素但賦予其不同樣式（但不是同一個元素）。
也就是說此範例是要選擇 id 是 main-title 且 classname 是 main-title2 的 &#x3C;h1>
*/
h1#main-title.main-title2 {
    color: red;
}
</code></pre>

接下來我們還要針對比較特別的選擇器進一步說明。

#### 通用選擇器

```css
/* 選擇全部 */
* {
    color: red;
}

/* 選擇 <p> 的第一層子分類中的 <h1> */
p > h1 {
    color: red;
}

/* <p> 「之後」的「第一個」相鄰的<h2>元素，改變 <h2> 的文字顏色 */
p + h2 {
    color: red;
}

/* <p> 「之後」的「所有」相鄰的<h2>元素，改變 <h2> 的文字顏色 */
p ~ h2 {
    color: red;
}
```

#### 屬性選擇器

我們可以在 HTML 元素上加上已經被定義的屬性或是自行添加的屬性：

```html
<p title="already-define" data-my-custom="my-custom-a">自行定義 attribute</p>
<p title="already-define" data-my-custom="my-custom-b">自行定義 attribute<
```

所以以下兩種寫法都可以得到相同的樣式結果：

<pre class="language-css"><code class="lang-css">[title="already-define"] {
<strong>    color: red;
</strong>}

[data-my-custom="my my-custom-a"] {
    color: red;
}

[data-my-custom="my my-custom-b"] {
    color: red;
}
</code></pre>

在上例中，要完全等於才有辦法套用樣式，但在實務上，通常我們會有基本型與其延伸出的變化型需求，所以屬性選擇器還可以有更多樣的選擇方式：

<pre class="language-css"><code class="lang-css">
/* 只要有 data-my-custom 就套用 */
[data-my-custom] {
    color: red;
}

/* 完全等於 my-custom-a 才套用 */
[data-my-custom="my-custom-a"] {
    color: red;
}

<strong>/* data-my-custom 開頭等於 my- 就套用 */
</strong>[data-my-custom^="my-"] {
    color: red;
}

/* data-my-custom 結尾等於 -a 就套用 */
[data-my-custom$="-a"] {
    color: red;
}

/* data-my-custom 值只要有出現 my- 就套用 */
[data-my-custom*="my-"] {
    color: red;
}

/* data-my-custom 值包含 my 就套用，但是以單字判斷 */
[data-my-custom~="my"] {
    color: red;
}

/* data-my-custom 值以 my 或 my- 開頭就套用 */
[data-my-custom|="my"] {
    color: red;
}

</code></pre>

#### 偽類、偽元素選擇器

因為太多了，所以不一一列舉，您可以至 w3school 觀看所有[偽類](https://www.w3schools.com/css/css_pseudo_classes.asp)與[偽元素](https://www.w3schools.com/css/css_pseudo_elements.asp)的選擇器。

### 權重

在某些形況下，我們會希望由一個基礎樣式擴充出不同樣式，我們可以使用這樣的方式撰寫：

```css
main p h1 {
    color: red;
}

/* 在 <h1> 多加一個 class="change-title-colo" */
main p h1.change-title-color {
    color: green;
}
```

\<h1> 會先找到紅色，之後又找到綠色，然後判斷綠色為最終樣式進而應用。為什麼會判斷綠色為最終樣式呢？

CSS 的最終樣式，取決於其重要的程度。在元素當中，我們可以為其增加 id 與 class 屬性，在 CSS 當中則有各式選擇器、偽類、!important、inline style 會影響權重，總的來說，可以下圖來表示重要程度：

<figure><img src="https://i.ibb.co/tK2jYKM/CSS-specificity.png" alt=""><figcaption><p><a href="https://muki.tw/tech/html-css/css-specificity-document/">https://muki.tw/tech/html-css/css-specificity-document/</a></p></figcaption></figure>

可以將權重分成五個數字，其構成為 !important - inline style - id - class - element，越左邊代表重要程度越大。例如：h1 + p::first-letter 可分成 h1、p、與 ::first-letter，而這三個都是屬於最右邊的數字所以就會是 0-0-0-0-3。

而 \*、+、>、\~ 和否定則不影響權重。

{% hint style="warning" %}
如果我們 CSS 寫錯了，或是瀏覽器不支援，\
該 CSS 將會被忽略，也就是不管它，當作沒有這一個東西存在，也就不會算進去權重裡。\
通常我們會利用工具來檢驗沒有使用到/沒有作用的 CSS 以提高效能。
{% endhint %}

### 小結

善用選擇器將會讓效能、維護性、可讀性、易用性提高非常多，請務必練習各種選擇器的方式。

### 作業

線上有很多 [CSS 選擇器的遊戲](https://flukeout.github.io/)網站挑戰看看，增強選擇的功力。

### 參考來源

* [How CSS works](https://developer.mozilla.org/zh-TW/docs/Learn/CSS/First_steps/How_CSS_works)
* [Rendering Performance](https://web.dev/rendering-performance/)
* [強烈推薦收藏好物 – CSS Specificity (CSS 權重一覽)](https://muki.tw/tech/html-css/css-specificity-document/)
* [金魚都能懂的 CSS 選取器 - 金魚都能懂了你還怕學不會嗎](https://ithelp.ithome.com.tw/users/20112550/ironman/2799?sc=iThelpR)
