pseudo-class vs pseudo-element
CSS v3 之前 (CSS v1, CSS v2) 沒有在語法上明確的區分 pseudo-class 和 pseudo-element 之間的不同. 二個都是以單一個 : 字元開頭.
但 CSS v3 的語法有明確的區分 pseudo-class 和 pseudo-element. 不過現行的 browser 為了相容性的原故並沒有嚴格區分此二者的語法.
- pseudo-class 偽類別: 以單一個 : 字元開頭.
區別: 偽類別用來標示 (整個) 元素的某個特殊狀態 (如: :hover 是滑鼠停在它上面的時候). - pseudo-element 偽元素: 以 :: 開頭 (二個 : 字元).
區別: 偽元素用來選取元素的部份內容, 或用來插入特定內容.(註一) (一共只有 5 種) - ::before 在作用元素的前面外加內容.
- ::after 在作用元素的後面外加內容.
- ::first-line 選取元素的第一行.
- ::first-letter 選取元素的第一個字.
- ::selection 選取元素被選取的部份.
另一個區別是 pseudo-class 的作用標的是固定/靜態的. pseudo-element 的作用標的是動態生成的.
註一: 其實簡單一點說, pseudo-element 是產生了一個在原 html 文件中不存在的 element. 這個說法 ::before 和 ::after 我們可以很容易理解. 但另外三個就好像說不通? 其實也不是說不通, 因為平時我們要標定部份的元素不都要手動加<span>嗎? 所以另外的這三個我們都可以認為是將 element 原本的內容取出一部份轉成 <span>. 這不就是了嗎? 你認為呢?
:not() 是一種 pseudo-class. 可以是其他 selector 的修飾(直接和其他 selector 黏在一起), 或者是獨立的 selector.
不管是作為獨立的 selector, 或修飾其他 selector, 放在 :not() 括號中的才是重中之重, 它可以是以下的簡單 selector:
- universal selector: * (這個應該沒意義吧, 要再查一下)
- type selector: tag_name
- class selector: .class_name
- id selector: #id_name
- attribute selector: 各式的 [attr_selector]
- pseudo-class: 但不包含 :not() 自己.
pseudo-element(這個不支援喔! 我故意的寫成刪除狀態)
其實不只如此, 組合選擇器 (combined selector, 用 combinator 組合起來的) 或者選擇器列表 (selector list, 用 , 串起來的) 也都可以.
- 組合選擇器:
- 後代組合子 (descendant combinator): SP 字元
A 全部階層的後代 B. 例: .notes p - 子代組合子 (child combinator): > 字元
A 的子代 (第一層) B. 例: .notes > p - 一般相鄰組合子 (general sibling combinator): ~ 字元
A 同層後續全部的 B. 例: #sect_1 ~ .notes - 緊密相鄰組合子 (adjacent sibling combinator): + 字元
A 同層後續緊鄰的 B. 例: img + p.img_caption
- 後代組合子 (descendant combinator): SP 字元
- 選擇器列表:
簡單選擇器或組合選擇器用 , 串起來的. 它的功能相檔於邏輯運算 OR.
例如: A:not(B, C) 意思是 A:not(B OR C) 展開括號之後得到 A:not(B) AND A:not(C).
另外 :not() 可以串接, 相當於作了邏輯運算 AND. 例如: A:not(B):not(C) 意思是 A:not(B) AND A:not(C).
所以 A:not(B, C) 和 A:not(B):not(C) 這二種寫法都是在 A 裡同時排除 B 和 C. 不過 A:not(B, C) 是比較新的語法; 相對的 A:not(B):not(C) 的寫法相容性要比較好一些.
不支援的部份及注意事項
- 不支援巢狀使用.
所以 :not() 的括號裡可以放 pseudo-class, 卻不可以再放一次自己. - 括號裡不支援 pseudo-element:
再重覆一次: 括號裡不可以放 pseudo-element.
注意一:
[id] 會選到全部有設 id 的任何元素; 同理可證 [class] 會選到全部有設 class 的任何元素. 但 :not([id]) 和 :not([class]) 卻隱含了一個思考誤區, 稍一不慎就陷入此一錯誤中. 沒錯, 它確實選到全部沒有設 id (或 class) 的任何元素, 包含 <body>. 各位請注意: CSS 設定有很多是會向下繼承給後代的, 所以有時候效果就好像是選取了全部的元素. 要解決這個問題, 我們應該要想辦法適當的縮小選取範圍. 例如: 前面多指定 tag (即 tag:not([class])), 或者使用組合選擇器也 OK.
例如: 如果 div.notes p:not([class]) 是 OK 正常的, div.notes :not([class]) 則可能 NG, 不正常. 因為 div.notes 內部可能含有非 <p> 的 element, 我們設定的 CSS 就有可能漏到那邊去了.
注意二:
使用時注意 :not() 的負邏輯, 尤其是使用選擇器列表. 你可能誤認為下列 CSS, 應該是同時排除 input.disabled 和 input.read-only. 事實上, , 是 grouping, 是聯集, 是 OR 邏輯.
#form_A input:not(.disabled),
#form_A input:not(.read-only) {
...
}
正確的寫法應是:
#form_A input:not(.disabled):not(.read-only) { ... }
/* 或者是 */
#form_A input:not(.disabled, .read-only) { ... }
因為 A:not(B), A:not(C) 這種寫法幾乎完全沒有作用. 原因是 A:not(B) OR A:not(C) 的功能是在 A 裡排除 B 和 C 二者的交集. 所以如果在 A 裡 B 和 C 互斥 (通常是這種狀況), 則這種寫法無法排除任何元素; 除非在 A 裡 B 和 C 有交集, 這種寫法才會有作用: 排除二者的交集.
幾個使用 :not() 的例子
:not(:first-child) (非第一個子元素), :not(:last-child) (非最後一個子元素).
.box li:not(:first-child) {
border-top:solid 1px white;
}
.box li:not(:last-child) {
border-bottom:solid 1px #d1ebf3;
}
- 第一行是 box 類別的後代 <li> 元素 (第一個除外)
- 第二行是 box 類別的後代 <li> 元素 (最後一個除外)
這二個都是用於設定元素與元素之間 (<li>) 的 CSS.
選取沒有設定某屬性 (attribute) 的某元素, 請用 tag[attr_name].
例如: 選取沒有設定 type 屬性的 <ol> 元素的所有第一層子代 <li> 元素.
ol:not([type]) > li {
list-style: decimal;
}
這個可以修改 ol 列表的計數符號. 所以 <ol type='alpha'>的第一層子代 <li> 不會被選取; <ol>的第一層子代 <li> 則會被選取.
又如: 選取 div.notes 元素的第一層子代 <p> 元素中沒有設定 id 屬性者.
div.notes > p:not([id]) {
margin-left: 3em;
}
選取有設定 class 屬性的元素 (任意值, 只要有就可以) 用 tag[class].
選取沒有設定 class 屬性的元素用 tag:not([class]). 例如:
div.notes > p:not([class]) {
padding-left: 3em;
display:block;
}
上例是選取 div.notes 元素的第一層子代元素 p 中沒有指定 class 屬性值元素. 所以 <div class='notes'>的第一層子代 <p class='any'> 不會被選取; 第一層子代 <p> 或 <p id='note1'> 則會被選取.
別忘了選取特定 class 的元素是用 .class_name, 不要傻傻的用 [class="class_name"] (比較慢而且優先層級比較低).
table:not(.hljs-ln) {
border:2px solid black;
border-collapse: collapse;
}
留言列表