天天看點

CSS基本功從頭練之Selector

CSS一直是我的短闆,從來沒有系統學過,一直都是使用第三方的樣式庫,或者在網上找點資料copy。最近感覺應該系統的梳理一下,否則很多概念還是不太清晰。還是屬于邊學邊寫的資料,難免各種漏洞,希望大家多指正。

Selector(選擇器)

為什麼會有選擇器這個概念?因為樣式最終是要應用到HTML的元素上的,那麼哪一類樣式應該應用到什麼元素這個問題就催生了選擇器的誕生。總體來說,Selector分标簽選擇器、類選擇器、ID選擇器和屬性選擇器

标簽選擇器

顧名思義是以HTML标簽作為篩選依據的,比如下面的代碼中,我們的可見标簽一共有:

<html>

<body>

<div>

<label>

<input>

<output>

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div>
    <label for="weight">體重</label>
    <input id="weight" type="number">
  </div>
  <div>
    <label for="height">身高</label>
    <input id="height" type="number">
  </div>
  <div>
    <label for="bmi">BMI</label>
    <output id="bmi"></output>
  </div>

</body>
</html>複制代碼
           

如果我們在css中有下面的定義,那麼我們其實是對所有

<body>

标簽(雖然事實上隻有一個)應用樣式背景色

#DCEDC8

,而對所有

<input>

标簽應用樣式背景色

#8BC34A

body {
  background-color: ;
}

input {
  background-color: ;
}複制代碼
           

應用body和input标簽樣式的效果

類選擇器

類選擇器的篩選标準是用類來确定的,就是在html标簽中,我們一般可以用

class="blablabla"

來完成樣式的類指定。現在我們改寫HTML,把所有label指定一個

class="label"

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div>
    <label class="label" for="weight">體重</label>
    <input id="weight" type="number">
  </div>
  <div>
    <label class="label" for="height">身高</label>
    <input id="height" type="number">
  </div>
  <div>
    <label class="label" for="bmi">BMI</label>
    <output id="bmi"></output>
  </div>

</body>
</html>複制代碼
           

然後在css中加上一個類樣式定義,在css中我們在類名的前面加上一個

.

來表示這是個類樣式定義。

.label {
  color: ;
}複制代碼
           

使用label類樣式定義後的效果

ID選擇器

我們看到上面的HTML代碼中,有一些元素是有

id

這個屬性的,那麼這個選擇器當然就是用來選擇

id="blablabla"

的元素的。如果我們在css中給BMI結果加入一個ID選擇器,放大結果的字型。

#bmi {
  font-size: xx-large;
}複制代碼
           

應用了ID選擇器的效果

屬性選擇器

屬性選擇器就是對HTML标簽中含有的屬性進行篩選,比如上例中我們如果想對标簽中

for

屬性、值為

weight

的進行特殊處理,那麼我們可以看到下圖的效果。

label[for="weight"] {
  color: ;
}複制代碼
           

應用屬性選擇器的效果

其實我感覺前面的ID選擇器、類選擇器甚至标簽選擇器都應該是屬性選擇器的一種特殊形式,比如我們其實把

#bmi

那段代碼注釋掉,換成屬性選擇器:選擇

id="bmi"

的形式效果是一樣的。

/* #bmi {
  font-size: xx-large;
} */

output[id="bmi"] {
  font-size: xx-large;
}複制代碼
           

屬性選擇器的花樣最多,下面我們來看看,如果不用

=

,而使用

~=

是什麼效果。我們把bmi的label中的for改成

for="weight height"

<div>
    <label class="label" for="weight height">BMI</label>
    <output id="bmi"></output>
  </div>複制代碼
           

然後在css中用

~=

替代

=

看看會發生什麼?我們看到體重和BMI都應用了

#FF4081

這個顔色。也就說

~=

表示選擇所有含有等号後面的值的元素。

label[for~="weight"] {
  color: ;
}複制代碼
           

使用 `~=` 代表選擇含有該值的所有元素

但是注意一點,

~=

後面的一定是一個完整的屬性值,而不是含有這個字元串就行,比如上面HTML中如果我們寫成

for="weight1 height"

那麼這個選擇器就無法生效了。

css1中還支援一種符号

|=

,它會選擇所有以等号後的值開頭的元素,同樣的,這裡的開頭指的是完整屬性值而不是字元串意義上的開頭。那麼問題來了,有沒有辦法選擇字元串呢?css3中增加了

^=

$=

*=

這幾個符号,是專門處理字元串這種需求的。題外話感覺這幾個操作符很像正規表達式中的。

還是上面的例子,我們的html如下,注意bmi的label的for中是

weight1

,而體重label的for中是

weight

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.umd.js"></script>
  <title>JS Bin</title>
</head>
<body>
  <div>
    <label class="label" for="weight">體重</label>
    <input id="weight" type="number">
  </div>
  <div>
    <label class="label" for="height">身高</label>
    <input id="height" type="number">
  </div>
  <div>
    <label class="label" for="weight1 height">BMI</label>
    <output id="bmi"></output>
  </div>

</body>
</html>複制代碼
           

css中我們使用

^=

來試驗一下,你會發現選擇器又生效了。

label[for^="weight"] {
  color: ;
}複制代碼
           

使用 `^=` 選擇以字元串xxx開頭的元素

同樣的如果我們換成下面的css,你會發現所有的label都變色了,因為都是

eight

這個字元串結尾的

label[for$="eight"] {
  color: ;
}複制代碼
           

`$=`選擇以字元串xxx結尾的所有元素

這時你會問,不對啊,bmi的label是

weight1

啊,但是請看仔細

for="weight1 height"

,這個字元串的最後是

height

*=

是選擇字元串中包含某個值的元素,遇到它的話我比較好奇的是它能不能選擇空格,因為

for="weight1 height"

中含有一個空格。于是我做了個實驗,用如下的css證明了是可以選擇空格的。

label[for*=" "] {
  color: ;
}複制代碼
           

`*=`選擇包含xxx字元串的元素

上下文選擇器

如果僅有上面這些也還不錯,css的強大或者說複雜在于還特麼能組合。這個上下文選擇器可以看作組合的一種,它利用多種符号連接配接标簽選擇器來實作根據上下文選擇元素的目的。

還是用執行個體說話,首先最簡單的組合符号

,

,為了看的更清楚一些,我們重新定義HTML:在最外面包了一層

div

,并且給每一層

div

都指定了一個樣式類。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.umd.js"></script>
  <title>JS Bin</title>
</head>
<body>
  <div class="content">
    <div class="weight">
      <label class="label" for="weight">體重</label>
      <input id="weight" type="number">
    </div>
    <div class="height">
      <label class="label" for="height">身高</label>
      <input id="height" type="number">
    </div>
    <div class="bmi">
      <label class="label" for="weight1 height">BMI</label>
      <output id="bmi"></output>
    </div>
  </div>
</body>
</html>複制代碼
           

css

中為幾個

div

定義背景色,以便看的更清楚些。然後利用

,

定義了

div,label

的padding是

20px

...
.weight {
  background-color: gray;
}

.height {
  background-color: silver;
}

.bmi {
  background-color: darkgray;
}

.content{
  background-color: brown;
}

div,label {
  padding: ;
}複制代碼
           

,

這種就比較簡單,就是多個标簽都使用這個樣式,我們來看看效果:

采用了`,`表示“和”

隻有div時的效果,仔細看會發現文字靠左邊緣近了一些

隻有label時的效果

這個操作符我認為隻起到節省代碼的作用;-)

後代選擇器 (空格)

下面我們看看

(空格)這個操作符,還是為了更明顯,我們在HTML中的最外層div之外加一行

我們在css中加上下面的定義,我們會看到,div内部的所有label的文字都變大了,但外部的沒有。是以

x y

表示選擇在

x

元素内部的所有

y

div label {
  font-size: x-large;
}複制代碼
           

` `空格表示在div内部的所有label

子選擇器

>

那麼下面我們看看

>

,同樣需要改造一下HTML,在

<div class="content">

下加入下面的代碼。

<p>
  <label for="something">我的父節點不是div,是以沒有變大</label>
</p>複制代碼
           

将css改成

div>label {
  font-size: x-large;
  padding:;
}複制代碼
           

下面看看效果,剛剛加入的那個label文字沒有變大的原因在于它的父節點是

<p>

`div>label` 符号篩選父節點為div的label元素

“親兄弟”選擇器

+

接下來的這位就有意思了

+

,你如果把

div+label

直接套用到上面的HTML中,會發現沒什麼作用,哪個字型也沒變大。原因是這個符号是選擇div 之後 的 緊挨着 div的label元素。

那麼我們的實驗之前,請把下面的代碼插入到最外層div之後

<label for="something">我不在div中但緊挨着div,是以變大了</label>
<label for="something">我雖然在div後但沒有緊挨着div,是以沒有變大了</label>複制代碼
           

`+` 指的是緊挨着前面的元素的所有元素

"兄弟連"選擇器

~

有看後面的就有看前面的,接下來就是

~

閃亮登場了,

div~label

是個什麼效果捏? 事實證明

x~y

是用于選擇前面有

x

的所有

y

div~label {
  font-size: x-large;
  padding:;
}複制代碼
           

`div~label` 用于選擇之前有div的所有label

僞類

為什麼叫這個名字?我也不知道,感覺有點怪,聽說一個說法是它們很像類,但我真沒看出哪兒像。僞類一般都是以

:

開頭,也不光是僞類的,僞元素也是

:

開頭。

連結僞類

首先看連結僞類,這個其實沒什麼好講,就是因為連結有幾個狀态,普通的選擇器無法篩選出來導緻硬生生的造出來這幾個東東。需要注意的是,這些貨必須按着下面的順序給出才可以生效。其實我實驗了一下,link和visited調換位置沒影響,其他按順序是因為這幾個狀态有時有重疊,寫錯順序會導緻樣式被覆寫。比如滑鼠按下未擡起其實同時也滿足hover的條件,如果我們把hover放在最後,active放在前面,那麼這時就會以最後的樣式(hover)覆寫前面的樣式(active)

  • link: 沒有通路過也沒有滑鼠懸停或點選的狀态。
  • visited:使用者點選過這個連結之後的狀态。
  • hover:滑鼠指針正懸停在連接配接上。
  • active:連結正在被點選(滑鼠在元素上按下,還沒有釋放)。

“選中狀态”僞類

再來看

:focus

僞類,這個也是由于輸入框處于聚焦狀态時無法通過其他選擇器選取而特别定制的,我們看一下效果

input:focus {
  background-color: ;
}複制代碼
           

體重輸入框聚焦的狀态

同理,還有類似的對于複選框、單選框等選中狀态的選擇所設計的

:checked

;為元素禁用和激活狀态所設計的

:enabled

:disabled

。這些就不舉例了,比較簡單,如果有坑,請指教。

“排頭兵”僞類

:first-letter

:first-line

:first-child

這幾個跟在某個元素後面的作用是選取該元素的第一個文字(英文的話是字母)、第一行和父元素的第一個子元素中的所有該元素。還是看圖說話吧。

我們把體重的selector加了一個首字母僞類放大字型200%,效果如下圖,另兩個的效果類似,隻不過是第一行或者第一個子元素,自己可以實驗一下。

.weight:first-letter {
  font-size:;
}複制代碼
           

首字大寫的效果

“字首”和“字尾”僞類

為什麼叫它們“字首”和“字尾”呢?因為它們是作用于選擇内容之前或之後的,為什麼要設計這個選擇器呢?我們的BMI電腦目前的兩個輸入值都是沒有機關的。如果我們希望增加一個機關的話,當然可以在HTML頁面增加,但是如果對于某一類值它們的機關就是某些文字的話,這麼做就有點累。我們給css加上下面的樣式看看效果。

.weight::after {
  content: "公斤";
}

.height::after {
  content: "厘米";
}複制代碼
           

另外一個比較常見的技巧是利用這個僞類去改造預設的控件樣式,比如複選框預設是方塊型,如何改造成圓形呢?我們就可以先把複選框中的原有表現形式(方塊)隐藏起來,然後利用“字尾”僞類畫出一個圓來。

//html
<input type="checkbox" class="check">
//css
.check {
  background-color: #8BC34A;
  width: 40px;
  -webkit-appearance: none;
  appearance: none;
}
.check::after {
  content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#fff" stroke-width="3"/></svg>');
}複制代碼
           

圓形複選框

“正着數和倒着數”僞類

css增加一堆很類似數組或集合中常用的選擇器,這一類的大部分都是成對的,可以記成正着數和倒着數。為了友善記憶,我就起名叫“正着數和倒着數”僞類了。這一類有好多,包括選擇首尾的:

:first-of-type

:last-of-type

:first-child

(這個不是css3引入的),

:last-child

;第n個子元素的

:nth-child(n)

:nth-last-child(n)

;第n個某類型子元素

:nth-of-type(n)

:nth-last-of-type(n)

;當然對于特殊情況,比如隻有一個的會有專門的處理:

:only-child

:only-of-type

應用這種選擇器可以非常友善的打造一些效果,比如交替顔色的表格。

table {
    width: ;
}

tr:nth-child(even){background-color: }複制代碼
           

交錯顔色的表格

這裡有問題了,這個

even

是怎麼回事?這一類Selector是可以接受表達式作為參數的,而

even

odd

作為兩個特别常用的東東被認定成關鍵字,其實

nth-child(even)

可以改寫成

nth-child(2n)

nth-child(odd)

可以改寫成

nth-child(2n+1)

。是的,如果你願意可以寫出3的倍數,5的倍數等等序列等等。