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() 語法


: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
  • 選擇器列表:
    簡單選擇器或組合選擇器用 , 串起來的. 它的功能相檔於邏輯運算 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 裡同時排除 BC. 不過 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.disabledinput.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 裡排除 BC 二者的交集. 所以如果在 ABC 互斥 (通常是這種狀況), 則這種寫法無法排除任何元素; 除非在 ABC 有交集, 這種寫法才會有作用: 排除二者的交集.

幾個使用 :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;
}

arrow
arrow

    MagicJackTing 發表在 痞客邦 留言(0) 人氣()