網頁三大件 HTML、CSS、JavaScript,其中 HTML 負責網頁模版的部分(即便到後面使用 JS 框架建造虛擬 DOM,開發者們依舊保留了 HTML 的模板樣式,如 Vue 的 template、React 的 JSX 等);而 JavaScript 則負責網頁的動態部分,如操作 dom、抽換 class、監聽事件處理等。
而本篇的主題:CSS 則是負責網頁標籤的樣式部分。CSS 的盒子模型能夠處理元素的覆蓋區域大小,控制元素的表現形式(flex、grid、table、block、inline),還有其他如背景、字體操作。CSS 幾乎囊括了一切開發者能想到對元素樣式的修改,合理靈活的運用 CSS 幾乎能做出任何你想得到的效果。
然而在聲明樣式表的同時有一個最重要的能力,也就是選擇器(Selector),CSS 需要透過選擇器材能夠定位到樣式真正生效的元素上。本篇就來全盤解析一下 CSS 的選擇器到底有哪些,以及如何使用。
CSS Selectors MDN | https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Selectors |
在開始介紹一個個選擇器之前,我們需要先來將選擇器分類,如下表:
其中基礎選擇器
定義了最基本形式的選擇器類型,可以用於指定特定目標元素特徵;複合選擇器
則定義那些多個元素相關連的,由元素間的關聯性來決定的樣式;最後一種偽選擇器
也就是狀態選擇器,再加上一些特殊的複合選擇器,詳細直接進入說明會更清楚明瞭。
tagName
由於 CSS 標籤都是套用在 DOM 樹上,標籤選擇器則可以透過直接指定標籤來選定這些元素,語法如下:
tagName {
/* attributes */
}
<body>
<h1>Titleh1>
<ul>
<li>item1li>
<li>item2li>
<li>item3li>
<li>item4li>
ul>
<p>Paragraph 1p>
body>
body {
margin: 0;
height: 100vw;
}
li {
line-height: 30px;
font-size: 15px;
}
p {
color: red;
}
.className
類選擇器透過指定標籤的 class
屬性中的字符串來選定元素,語法如下:
.className {
/* attributes */
}
<div class="wrapper">
<div class="list">
<div class="item">1div>
<div class="item">2div>
<div class="item">3div>
<div class="item">4div>
div>
div>
.wrapper {
width: 1680px;
margin: 0 auto;
}
.list {
max-width: 500px;
padding: 10px 40px;
}
.item {
color: red;
font-size: 15px;
}
#idName
類選擇器透過 class
屬性來指定元素,而 ID 選擇器則透過 id
屬性來指定元素。與 class
不同的是,id
屬性同時只會在一個元素上作用,也就是指定特定元素的唯一標示符,語法如下:
#idName {
/* attributes */
}
<div id="sample">div>
#sample {
border-bottom: 1px solid red;
}
*
有時候我們可能需要將某些樣式套用到所有標籤上,就可以使用通配符 *
,將會匹配所有元素標籤。
**注意!**然而並不推薦這樣的使用方式,因為會使 CSSOM 選染樹的開銷急劇增加,CSS 選擇器的使用應能越接近渲染數底部越好。通常通配符應該與其他選擇器共同作用來縮減目標元素的範圍,以減輕渲染數的負擔
* {
/* attributes */
}
* {
margin: 0;
font-size: 12px;
}
selector[attr="value"]
有時候我們想選擇的對象並沒有特定的 class
或 id
值,而是想透過標籤屬性的特徵來指定元素,這時候就可以使用屬性選擇器,屬性選擇器內部又可以分成多種屬性值的判別方式
/* 指定屬性存在 */
selector [attr] {
}
/* 指定屬性值 */
selector [attr='value'] {
}
/* 屬性值為空格隔開的字符串列表,其中存在指定屬性值 */
selector [attr~='value'] {
}
/* 指定屬性值或以指定屬性值為前綴,如 value 或是 value- */
selector [attr|='value'] {
}
/* 以指定屬性值開頭 */
selector [attr^='value'] {
}
/* 以指定屬性值結尾 */
selector [attr$='value'] {
}
/* 包含指定屬性值 */
selector [attr*='value'] {
}
/* operator、value 可為上述形式,i 表示忽略大小寫 */
selector [attr operator value i] {
}
selector
:為三種基本形式 tagName
、.className
、#idName
之一<div title="a b c">div>
div[title~='b'] {
}
selector:state
HTML 元素通常會自帶一些狀態,而狀態選擇器可以選擇指定狀態下的元素形式,如焦點(focus)、訪問(visited)、激活(active)等,以下列出選擇器語法和常見狀態
selector :state {
}
State | 狀態描述 |
---|---|
active | 激活狀態(例如鼠標點擊下的狀態) |
checked | radio 選中時的狀態 |
disabled | 禁用狀態(輸入框、選擇器) |
enabled | 啟用狀態 |
focus | 獲得焦點的狀態 |
hover | 鼠標懸浮在元素上的狀態(觸控屏的判定有問題) |
valid | 表單元素未通過驗證的狀態 |
link | 尚未訪問的鏈結 |
visited | 已訪問過的鏈結 |
optional | 非必填的表單元素 |
required | 必填的表單元素 |
target | id 與當前 URL 錨點相同的元素 |
<div id="root">div>
<input id="input-name">input>
<a id="to-github">a>
#root:hover {
outline: 1px solid red;
}
#input-name:disabled {
background-color: lightgray;
}
selector, selector, ...
有時候我們同一組樣式想要套用在多個擇器上,透過 ,
來連接多個選擇器
selector,
selector,
... {
}
<div class="item1">div>
<div class="item2">div>
<div class="item3">div>
<div class="item4">div>
.item1,
.item2,
.item3,
.item4 {
font-size: 15px;
}
AB
、A B
、A,B
這邊可能會出現三種容易搞混的選擇器(後代選擇器下面有介紹),分別是 AB
、A B
、A,B
,直接上代碼:
<div class="a b">1div>
<div class="a">
<div>
<div class="b">2div>
div>
div>
.a.b {
color: red;
}
.a .b {
color: orange;
}
.a,
.b {
font-size: 20px;
}
AB
的含義是匹配同時滿足 A 和 B 兩個選擇器的元素A B
為後代選擇器,在後面的段落有說明A,B
表示匹配 A 或 B 的所有元素A + B
這個選擇器用於匹配直接相鄰的兄弟元素(後面的一個),語法如下
selector + selector {
}
<ul>
<li>item1li>
<li>item2li>
<li>item3li>
<li>item4li>
ul>
<div style="display: flex">
<div class="tag">tag1div>
<div class="tag">tag2div>
<div class="tag">tag3div>
div>
li + li {
margin-top: 5px;
}
.tag + .tag {
margin-left: 10px;
}
A ~ B
這個與上一個選擇器相比沒有那麼嚴格,只要是同層級的兄弟元素都能夠匹配,不一定要直接相鄰
selector ~ selector {
}
<div>
<div class="a">1div>
<div class="b">b-1div>
<div class="a">2div>
<div class="b">b-2div>
<div class="a">3div>
<div class="b">b-3div>
<div class="a">4div>
div>
.a ~ .a {
background-color: red;
}
.b ~ .b {
background-color: orange;
}
A > B
直接子代選擇器需要滿足 A 匹配父元素而 B 匹配直接子代的子代元素
selector > selector {
}
<div class="a">
<div class="b">1div>
div>
<div class="a">
<div>
<div class="b">2div>
div>
div>
.a > .b {
font-size: 30px;
}
class="a"
的直接子代這邊對於直接子代的限定比較嚴格,也是邏輯上限制較大的匹配模式,相較於後面要介紹的後代選擇器,在開銷的表現上比較好,也應該優先選擇直接子代選擇器
A B
相較於上面的直接子代選擇器,後代選擇器的條件比較寬鬆一些,只要匹配 A 的元素的任意子代匹配 B 就能夠套用樣式
selector selector {
}
**注意!**這邊容易跟組選擇器(A, B
)和聯合選擇器(AB
)搞混,在上面的組選擇器中有說明
<div class="a">
<div class="b">1div>
div>
<div class="a">
<div>
<div class="b">2div>
div>
div>
.a > .b {
font-size: 30px;
}
class="b"
的元素都是 class="a"
的元素的後代selector:pseudo-class
上面介紹過了狀態選擇器,而"狀態"類是偽類子級,這邊將介紹更完整的偽類。
selector :pseudo-class {
}
除了上面介紹過的一些狀態選擇器之外,還存在一些根據元素順序匹配的偽類:
偽類 | 描述 |
---|---|
first | 與 @page 連用,指打印時第一頁的元素 |
left | 與 @page 連用,指打印時頁面左側的樣式 |
right | 與 @page 連用,指打印時頁面右側的樣式 |
first-child | 一組兄弟元素內的第一個元素 |
first-of-type | 一組兄弟元素內的第一個符合類型的元素 |
last-child | 一組兄弟元素內的最後一個元素 |
last-of-type | 一組兄弟元素內的第一個符合類型的元素 |
nth-child(an + b) | 一組兄弟元素內中第 an + b 個元素(n 為任意數,a、b 為指定常數) |
nth-last-child(an + b) | 與 nth-child 類似,由後往前數 |
nth-of-type(n) | 一組兄弟元素內中第 n 個匹配的元素 |
nth-last-of-type(n) | 一組兄弟元素內中第 n 個匹配的元素 |
only-child | 一組兄弟元素內中唯一的元素 |
only-of-type | 一組兄弟元素內中唯一匹配的元素 |
<div>
<p>p1p>
<ul>
<li>li1li>
<li>li2li>
<li>li3li>
<li>li4li>
ul>
<p>p2p>
<ul>
<li>li5li>
<li>li6li>
<li>li7li>
<li>li8li>
ul>
<p>p3p>
div>
ul > li:nth-child(2) {
background-color: red;
}
div > p:nth-child(2n + 1) {
background-color: orange;
}
selector::pseudo-element
偽元素則是在選擇器中比較特別的存在,他不像是一般的選擇器改變已有標籤的樣式,反而更像是往匹配的元素的指定位置添加一個元素樣式,可能是提示文字或是模板文字,不過這種情況通常比較難以控制,所以需要小心使用
selector::pseudo-element {
}
以下列出常用的標準偽元素表:
偽元素 | 說明 |
---|---|
before | 將偽元素添加到匹配元素之前 |
after | 將偽元素添加到匹配元素之後 |
first-letter | 匹配元素的第一個字符,可用於首字符放大 |
first-letter | 匹配元素的第一行文字 |
selection | 匹配被用戶高亮的部分(就是用滑鼠框起來的部分啦 hhh) |
<div class="subtitle">跳轉頁面一div>
<a href="">link1a>
<div class="subtitle">跳轉頁面二div>
<a href="">link2a>
.subtitle::before {
content: '- ';
}
a::before {
content: '鏈結:';
color: lightgray;
font-size: 8px;
}
class="subtitle"
的元素前加上 -
,而第二個選擇器為每個鏈結加上前導文字以上就是 CSS 選擇器的完整介紹,基本上能夠熟練運用上述的選擇器,99% 的元素特徵任你組合,這些也基本就是選擇器的全部了。或許你會問,阿還有 @page
、@media
啊,那些就是另一種通屬於 @
的語法了,將在其他篇詳細解說。