# CSS選擇器

最基本的`id`，`class`和`descendant` selectors（子元素選擇器），在本文中我提到的眾多選擇器是在CSS3規範下的一部分，但是，作為結果，只有現代主流的瀏覽器可以使用，不過依然還是要把它們記下來。

## 基本選擇器

### 1.  \*

星號標誌會指向頁面上所有的元素。 很多人都會用這個訣竅來將`margin`和`padding`歸零。 雖說這個對於一個快速的測試是肯定沒問題的，但是我建議你永遠都不要將其應用於生產環境的代碼中。 它為瀏覽器帶來太多*負擔*，而且是完全沒必要的。

星號`*`可以同時被用於子對象選擇器中。

```css
* {
 margin: 0;
 padding: 0;
 box-sizing: border-box;
}
```

&#x20;星號`*`可以同時被用於子對象選擇器中。這樣可以指向所有的`#container` `div`的子對象。 同樣的，如果可能的話，盡可能不要使用這個方法。

```css
#container * {
 border: 1px solid black;
}
```

歸零CSS可以參考Reset Css章節

{% content-ref url="../qian-duan-san-xiong-di/css-ji-ben-shi-yong/css-div-pai-ban" %}
[css-div-pai-ban](https://information9527.gitbook.io/html/qian-duan-san-xiong-di/css-ji-ben-shi-yong/css-div-pai-ban)
{% endcontent-ref %}

### 2.  #X  - (ID)

&#x20;在選擇器前面加井號鍵可以允許我們指向`id`。 這是一個最常用的選擇器使用，不過當使用`id`選擇器的時候要注意。

```css
#container {
   width: 960px;
   margin: auto;
}
```

&#x20;`id`選擇器的規則非常的嚴格，而且因為他是唯一的，所以不允許被再次使用。 如果可能的話，首先嘗試使用tag名，這是一個HTML5版本的新元素，或者甚至試試偽類。

### 3.  .X -  (Class)

&#x20;這是一個`class`選擇器。 `id`和`class`的不同點就是class可以同時標記多個元素。 當你想要你的樣式應用到一組元素的時候你可以使用`class`。 或者，你也可以使用`id`來刻意讓一個單獨的元素使用特別的樣式。

```css
.error {
  color: red;
}
```

### 4. X Y

&#x20;最常見的選擇器是`descendant` selector（子對象選擇器）。 當你需要更明確的選擇某個目標時，你就使用這個選擇器。 舉個例子，假設你不想選擇**所有**的錨點對象，你只是想選擇所有的無序列表以下的錨點對象？ 這樣的情況就特別的需要使用子對象選擇器了。

```css
li a {
  text-decoration: none;
}
```

這個使用時機，通常都是有共通點的修改才建議使用。照上方敘述則是li  a  有關的都為`text-decoration: none;` ，若大量使用後期會比較難維護。

### 5. X

&#x20;如果你想要選擇當前頁面所有的相同`type`（種類）的元素，你會考慮使用`id`或者`class`如果你想保持程式碼的乾淨，就用type（類）選擇器好了。 如果你需要選中所有的無序列表，使用`ul {}`。

```css
a { color: red; }
ul { margin-left: 0; }
```

當然可以直接使用，但如同上個一樣建議有共通點才建議使用，不然請多多善用`id`或者`class`

### 6. X:visited and X:link

我們使用`:link`偽類來選擇所有的錨點標籤並且你還沒有點擊過。

作為備用，我們同時有`:visited`偽類，正如你期待的，這個允許我們應用特別的樣式到頁面上已經被點擊過或者訪問過的錨點標籤。

```css
a:link { color: red; }
a:visted { color: purple; }
```

### 7. X + Y

&#x20;這個被稱為相鄰兄弟選擇器。 它*僅僅*會選擇剛好在左邊元素之前的元素。 在這種情況下，僅僅第一個`ul`之後的段落()會被賦予紅色。

```css
ul + p {
   color: red;
}
```

### 8. X > Y

由於這個原因我們可以得出，使用子組合器有很多的性能上的利益。 事實上，當使用JavaScript為基礎的CSS選擇器引擎的情況下是非常推薦的。

一個`#container > ul`的選擇僅僅會選中那些包含`id`名`container`的`div`下的直接子對象`ul`。 它並不會指向，舉個例子，第一個`li`裡面的子對象`ul`。

```css
div#container > ul {
  border: 1px solid black;
}
```

普通的`X Y`和`X > Y`的不同是後者僅僅選擇它的直接的子對象。 舉個例子，考慮一下以下的情況。

```markup
<div id="container">
   <ul>
      <li> List Item
        <ul>
           <li> Child </li>
        </ul>
      </li>
      <li> List Item </li>
      <li> List Item </li>
      <li> List Item </li>
   </ul>
</div>
```

### 9. X \~ Y

&#x20;這個一般兄弟組合器和相鄰兄弟組合器`X + Y`非常相似，但是，更加不嚴格。 相鄰兄弟選擇器（ul + p）只會選擇剛剛好在前一個選擇器之前的第一個元素，而這個選擇器的範圍會更廣一點。 在我們上面的案例中，它會選擇所有的`p`元素，只要他們是在`ul`之後的。

```css
ul ~ p {
   color: red;
}
```

### 10. X\[title]

&#x20;該選擇器適用於*屬性選擇器*，在我們上面的例子裡，這會僅僅選擇所有包含有`title`屬性的的錨點對象。 那些並沒有title屬性的將不會接收到該特有的樣式。&#x20;

{% tabs %}
{% tab title="CSS" %}

```css
a[title] {
   color: green;
}
```

{% endtab %}

{% tab title="html" %}

```markup
<div id="container">
   <ul>
      <li> List Item
      <ul>
         <li> Child </li>
      </ul>
      </li>
      <li> List Item </li>
      <li> List Item </li>
      <li> List Item </li>
   </ul>

   <p> Lorem ipsum dolor sit amet, <a href="#" title="Some title">consectetur</a> adipisicing elit, sed do eiusmod tempor. </p>
   <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor. </p>
   <p> Lorem ipsum dolor sit amet, consectetur <a href="#">adipisicing</a> elit, sed do eiusmod tempor. </p>
   <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor. </p>
</div>
```

{% endtab %}

{% tab title="結果畫面" %}
![](https://3336654295-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MDPdvZ3NzJOlXMhEq_2%2F-Mb_rZZ3nLNVbX7qT8Rr%2F-Mb_sQDbX5zgkcTF2Wci%2Fimage.png?alt=media\&token=ec91c60a-20f9-4c83-bbb0-a5a1b78f60dc)
{% endtab %}
{% endtabs %}

## 進階選擇器

### 11. X\[href="foo"]

&#x20;上面這個小片段將為所有包含鏈接[*https://net.tutsplus.com*](https://net.tutsplus.com/)的錨點對象添加樣式； 他們將接收到我們的標誌性的綠色。其他的對象將保持不被改變的狀態。 其他的對象將保持不被改變的狀態。

{% tabs %}
{% tab title="CSS" %}

```css
a[href="https://net.tutsplus.com"] {
  color: #1f6053; /* nettuts green */
}
```

{% endtab %}

{% tab title="html" %}

```markup
   <div id="container">
      <ul>
         <li> List Item
         <ul>
            <li> Child </li>
         </ul>
         </li>
         <li> List Item </li>
         <li> List Item </li>
         <li> List Item </li>
      </ul>

      <p> Lorem ipsum dolor sit amet, <a href="#" title="Some title">consectetur</a> adipisicing elit, sed do <a href="http://nettuts.com">Nettuts</a> tempor. </p>
      <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor. </p>
      <p> Lorem ipsum dolor sit amet, consectetur <a href="#">adipisicing</a> elit, sed do eiusmod tempor. </p>
      <p> Lorem ipsum <a href="http://net.tutsplus.com">Nettuts+</a> sit amet, consectetur adipisicing elit, sed do eiusmod tempor. </p>
   </div>
```

{% endtab %}
{% endtabs %}

&#x20;這樣就可以工作了，不過，還是有一點僵硬， 如果這個鏈接確實是指向Nettuts+，但是，也許，這個路徑是*nettuts.com*而不是完整的url呢？ 在這種情況下，我們可以使用一點點普通表達式的語法在裡面。

{% hint style="info" %}

### 注意

我們將值放在了引號裡。 記住如果你使用JavaScript CSS選擇器引擎也要做同樣的事情。 如果可能的話，總是使用CSS3選擇器而不是非官方的方法。
{% endhint %}

### 12. X\[href\*="nettuts"]

&#x20;星號指定的值必須出現在屬性裡面的某個地方。 這樣，這就包括了*nettuts.com*、*net.tutsplus.com*、甚至是*tutsplus.com*。

請記住，這個是個非常寬泛的聲明。 如果這個錨點對象鏈接到某個並不是Envato的網站但其字符串裡面又包含了*tuts*在url又會怎麼樣呢？ 當你需要更精確的時候，使用`^`和`$`來分別指向開始或結束的字符串。

{% tabs %}
{% tab title="CSS" %}

```css
a[href*="tuts"] {
  color: #1f6053; /* nettuts green */
}
```

{% endtab %}

{% tab title="HTML" %}

```markup
   <div id="container">
      <ul>
         <li> List Item
         <ul>
            <li> Child </li>
         </ul>
         </li>
         <li> List Item </li>
         <li> List Item </li>
         <li> List Item </li>
      </ul>

      <p> Lorem ipsum dolor sit amet, <a href="#" title="Some title">consectetur</a> adipisicing elit, sed do <a href="http://nettuts.com">Nettuts</a> tempor. </p>
      <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor. </p>
      <p> Lorem ipsum dolor sit amet, consectetur <a href="#">adipisicing</a> elit, sed do eiusmod tempor. </p>
      <p> Lorem ipsum <a href="http://net.tutsplus.com">Nettuts+</a> sit amet, consectetur adipisicing elit, sed do eiusmod tempor. </p>
   </div>
```

{% endtab %}
{% endtabs %}

### 13. X\[href^="http"]

&#x20;這是一個小的腰帶狀包含有克拉符號的標誌。 這是最常見用在普通表達式裡面的一種標誌，一般會出現在字符串的開始。 如果你希望指向所有的包含`href`且開頭是`http`的錨點對象，我們可以使用上面所提到的相似選擇器。

```css
a[href^="http"] {
   background: url(path/to/external/icon.png) no-repeat;
   padding-left: 10px;
}
```

現在，如果我們希望為所有的，假設，指向照片的錨點來設置樣式。 在這種情況下，我們就需要搜索*結束*的字符串。

### 14. X\[href$=".jpg"]

&#x20;同樣的，我們使用普通的表達式符號`$`，來提到尾部的字符串。 在這種情況下，我們需要搜索所有包含鏈接到圖片的錨點——或者至少也是一個以`.jpg`結尾的url。 記住，這個選擇器肯定不能被用在`gifs`和`pngs`上。

```css
a[href$=".jpg"] {
   color: red;
}
```

### 15. X\[data-\*="foo"]

&#x20;參考到第8條，我們該如何來選中所有不同種類的圖片呢：`png`，`jpeg`，`jpg`，`gif`？ 好吧，我們需要創建多個選擇器，諸如：

```css
a[data-filetype="image"] {
   color: red;
}
```

```css
a[href$=".jpg"],
a[href$=".jpeg"],
a[href$=".png"],
a[href$=".gif"] {
   color: red;
}
```

&#x20;但是，這麼做太蛋疼了，而且還沒效率。 另一種解決辦法會使用自定義屬性。 如果我們添加自己的`data-filetype`屬性到每一個鏈接到圖片的錨點會發生什麼呢？

```markup
<a href="path/to/image.jpg" data-filetype="image"> Image Link </a>
```

然後，由於有這個*hook*在，我們可以使用基本的屬性選擇器來僅僅指向我們需要的那些錨點。

```css
a[data-filetype="image"] {
   color: red;
}
```

### 16. X\[foo\~="bar"]

這裡有一個特別的選擇器，如果你使用的會給你的朋友留下深刻的印象。 並不是所有的人都知道這個小訣竅。 這個標籤的標誌（`~`）可以讓我們分別指向那些有空格分開的多個屬性值。

接著使用上面的我們在第15點提到的自定義屬性，我們創建一個`data-info`的屬性，可以允許使用空格來列出我們需要的不同記錄。 在這種情況下，我們需要留下記錄來對應外部鏈接以及鏈接到圖片——只是舉個例子。

```css
a[data-info~="external"] {
   color: red;
}
 
a[data-info~="image"] {
   border: 1px solid black;
}
```

```markup
<a href="path/to/image.jpg" data-info="external image"> Click Me, Fool </a>
```

當這段基礎代碼到位以後，我們可以指向任何的其中一個值，這裡就需要使用這個\~標記屬性選擇的小技巧。

```css
/* Target data-info attr that contains the value "external" */
a[data-info~="external"] {
   color: red;
}
 
/* And which contain the value "image" */
a[data-info~="image"] {
  border: 1px solid black;
}
```

## 偽類選擇器

### 17. X:checked

&#x20;這是一個偽類，它僅僅會指向一個用戶端被選中的元素 - 像是*單選框*或者多選框。 就是像你想像的這麼簡單。

```css
input[type=radio]:checked {
   border: 1px solid black;
}
```

### 18. X:after

這個`before`和`after`的偽類實在是太虎了。 看起來，每天都有人在嘗試尋找新的且有創造性的方法來更有效的使用它們。 它們簡單的在選中的元素周圍生成內容。

很多人都是在嘗試解決clear-fix的時候被介紹使用這些類並嘗試用它們來hack。

```css
.clearfix:after {
    content: "";
    display: block;
    clear: both;
    visibility: hidden;
    font-size: 0;
    height: 0;
    }
 
.clearfix { 
   *display: inline-block; 
   _height: 1%;
}
```

&#x20;這個*hack*使用了`:after`偽類來添加一個空格到元素的後面，然後將它清除。 這是你應該放進你工具盒的一個完美的小訣竅，特別是當你想使用`overflow：hidden`的時候卻又不可能的情況下。

{% hint style="info" %}
&#x20;根據CSS3選擇器的說明，你其實應該使用兩個冒號`::`作為偽元素的語法。 然而，為了兼容性，用戶端也會接受單一冒號的使用。 事實上，在這裡，更明智的辦法還是使用單一冒號的版本到你的項目裡。
{% endhint %}

### 19. X:hover

&#x20; 這是個官方的術語用在`用戶活動的偽類`。 這個可能聽著比較奇怪，但其實不然。 你想要為用戶鼠標劃過的元素添加樣式麼？ 這一條就可以幫你完成工作！

```css
div:hover {
  background: #e3e3e3;
}
```

你會經常使用這個選擇器的，舉個例子，生成一個`border-bottom`到錨點對象，當鼠標劃過的時候顯示。

```css
a:hover {
 border-bottom: 1px solid black;
}
/*
專家提示 - 
 border-bottom: 1px solid black;
 看起來要比text-decoration: underline;更合適。
*/
```

{% hint style="info" %}

### &#x20;注意

舊版的IE瀏覽器不支持`:hover`偽類用在任何非錨點對像上。
{% endhint %}

### 20. X:not(selector)

```css
div:not(#container) {
   color: blue;
}
```

`negation`偽類特別的有用。 讓我們說，我想選擇所有的div，除了一個有`id`是`container`的。 上面這個小片段可以將工作完成的很完美。

或者，如果你想選擇所有的單個元素（不建議）除了段落對象，我們可以做如下：

```css
*:not(p) {
  color: green;
}
```

### 21. X::pseudoElement

我們可以使用偽元素（設計為`::`）來為元素的分段添加樣式，比如第一行、或者第一個文字等。 記得，這些必須作用到一個段落的元素中才能有效果。

> 一個偽元素是由兩個冒號構成的`::`

```css
p::first-line {
   font-weight: bold;
   font-size: 1.2em;
}
```

**指向段落中的第一個文字**

這個小片段是一個抽象的概念，可以找到頁面上的所有段落，並且找到僅僅是它們最開始的文字作為元素。這個最常被使用在創建報紙上每篇文章的第一個字母的樣式上。

```css
p::first-letter {
   float: left;
   font-size: 2em;
   font-weight: bold;
   font-family: cursive;
   padding-right: 2px;
}
```

&#x20;相似的，`::first-line`偽元素會按我們期待的，僅僅為第一行元素添加樣式。

### 22. X:nth-child(n)

```css
li:nth-child(3) {
   color: red;
}
```

還記得我們沒辦法從一疊元素中選擇特定的元素的那些日子麼？ 這個`nth-child`偽類會解決這些問題！

請注意，`nth-child`接受整數的參數，然而，這個參數不是以0為基數的。 如果你希望指向第二行物體，使用`li:nth-child(2)`。

我們甚至可以使用這個來選擇不同組合的子對象。 舉個例子，我們可以用`li:nth-child(4n)`來選擇所有的第四個列表中的物體。

### 23. X:nth-last-child(n)

如果你有一個在`ul`里數量龐大的列表，而且僅僅需要選擇倒數第三個物品要怎麼辦？ 與其使用`li:nth-child(397)`，不如使用`nth-last-child`來作為替代的偽類。

這種技術的工作原理幾乎和第十六點以後的方法相似，然而，不同的是它在集合的末尾開始和工作並反向數數字。

```css
li:nth-last-child(2) {
   color: red;
}
```

### 24. X:nth-of-type(n)

有時候，與其說選擇`child`，不如說你會需要根據`type`的元素來選擇。

想想一下，標記包含了5個無序列表。 如果你希望僅僅給第三個`ul`，並且你並沒有一個特別的`id`與之掛鉤，你可以使用`nth-of-type(n)`偽類來選擇。 在上面的小片段裡，只有第三個`ul`會在周圍有邊框。

```css
ul:nth-of-type(3) {
   border: 1px solid black;
}
```

### 25. X:nth-last-of-type(n)

&#x20;為了保持一致，我們同時可以使用`nth-last-of-type`來從尾部開始選擇列表，讓我們反過來數直到找到我們希望指向的目標。

```css
ul:nth-last-of-type(3) {
   border: 1px solid black;
}
```

### 26. X:first-child

這個結構性的偽類允許我們僅指向父元素的第一個子對象。 你會經常的使用到這個來去除第一個和最後一個列表物品的邊框。

舉個例子，如果你有一個很多行的列表，每個元素都包含`border-top`和`border-bottom`。 如果是這種情況，第一個和最後一個元素會看起來有點奇怪。

很多設計師都會使用class來命名`first`和`last`來修復這個問題。 作為替代的，你可以使用這些偽類去處理。

```css
ul li:first-child {
   border-top: none;
}
```

### 27. X:last-child

與`first-child`相反，`last-child`會指向父對像下的最後一個子元素。

{% tabs %}
{% tab title="CSS" %}

```css
ul > li:last-child {
   color: green;
}
```

{% endtab %}

{% tab title="html" %}

```markup
<ul>
   <li> List Item </li>
   <li> List Item </li>
   <li> List Item </li>
</ul>
```

{% endtab %}
{% endtabs %}

### 28. X:only-child

說真的，你可能會發現你永遠都不怎麼會用`only-child`這個偽類。 儘管如此，它依然是可用的，有時候你可能也需要它。

它允許你指向那些父對象*僅有*的一個子對像元素。 舉個例子，根據上面的片段，只有段落 - `div`的唯一子對象，會被上色變成紅色。

讓我們假設下面的代碼結構。

{% tabs %}
{% tab title="CSS" %}

```css
div p:only-child {
   color: red;
}
```

{% endtab %}

{% tab title="html" %}

```markup
<div><p> My paragraph here. </p></div>
 
<div>
   <p> Two paragraphs total. </p>
   <p> Two paragraphs total. </p>
</div>
```

{% endtab %}
{% endtabs %}

&#x20;在這個情況下，第二個`div`的段落不會被選中，只有第一個`div`。 只要你有多於一個子對象，only-child的偽類就停止作用。

### 29. X:only-of-type

```css
li:only-of-type {
   font-weight: bold;
}
```

這個結構性的偽類可以使用到很明智的地方。 它會指向那些在其父對象容器中沒有兄弟姐妹的元素。 舉個例子，我們來選中所有的`ul`，這些ul都只有一個列表元素。

首先，問問你自己要如何完成這個工作？ 你可以使用`ul li`，不過，這樣會指向*所有的*列表元素。 唯一的解決辦法就是使用`only-of-type`。

```css
ul > li:only-of-type {
   font-weight: bold;
}
```

### 30. X:first-of-type

`first-of-type`偽類允許你選擇第一個相同類的兄弟姐妹。

&#x20;現在，先試試不往下看，嘗試著搞清楚如何只選中“*List item 2*”。 當你搞明白了（或者放棄了），接著往下讀。

{% tabs %}
{% tab title="html" %}

```markup
<div>
   <p> My paragraph here. </p>
   <ul>
      <li> List Item 1 </li>
      <li> List Item 2 </li>
   </ul>
 
   <ul>
      <li> List Item 3 </li>
      <li> List Item 4 </li>
   </ul>   
</div>
```

{% endtab %}

{% tab title="css\_1" %}

```css
ul:first-of-type > li:nth-child(2) {
   font-weight: bold;
}
/*
解決方案1
有幾種不同的方法可以解決這個小測驗。 我們來回顧其中少數的幾個。 首先我們要使用first-of-type。

這個片段本質上來看可以這麼說，“找到頁面上的第一個無序列表，然後找到其最接近的子對象，
它們是列表下的元素。 接下來，接著向下過濾到僅選擇第二個列表中的元素。
*/
```

{% endtab %}

{% tab title="css\_2" %}

```css
p + ul li:last-child {
   font-weight: bold;
}

/*
另外一個選項是使用相鄰兄弟選擇器。
在這個情況下，我們可以看出ul是在p之前的對象，然後我們需要找到它裡面最後一個子對象。
*/
```

{% endtab %}

{% tab title="css\_3" %}

```css
ul:first-of-type li:nth-last-child(1) {
   font-weight: bold;   
}

/*
當我們想要使用這個選擇器的時候，我們可能會感覺到非常的不開心或者非常好笑。
這一次，我們抓取了頁面上的第一個ul，然後找到了第一個其內的元素，不過是反過來數的！ :)
*/
```

{% endtab %}
{% endtabs %}
