您好,登錄后才能下訂單哦!
本篇內容主要講解“CSS中的選擇器是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“CSS中的選擇器是什么”吧!
我們先了解一下選擇器的語法,然后深入了解背后相關的特性。
簡單選擇器
星號 —— *
通用選擇器,可以選擇任何的元素
類型選擇器|type selector —— div svg|a
也叫做 type selector, 也就是說它選擇的是元素中的 tagName
(標簽名) 屬性
tagName 也是我們平常最常用的的選擇器
但是因為 HTML 也是有命名空間的,它主要有三個:HTML
、SVG
、MathML
如果我們想選 SVG 或者 MathML 里面特定的元素,我們就必須要用到單豎線 |
,CSS選擇器里面單豎線是一個命名空間的分隔符,而HTML 里面命名空間分隔符是 冒號 :
。然后前面說到的命名空間是需要 @namespace 來聲明的,他們是配合使用的,但是這個命名空間的使用不是很頻繁,它的存在只是為了一個完備性考慮,HTML 和 SVG當中唯一一個重疊的元素名就只有一個 a
所以我們可以認為,類型選擇器就是一個簡單的文本字符串即可
類選擇器|class selector —— .class-name
以 .
開頭的選擇器就是 class 選擇器,也是最經典之一
它會選擇一個 class,我們也可以用空格做分隔符來制定多個 class 的
這個 .class
只要匹配中其中一個就可以了
ID 選擇器|id selector —— #id
以 #
開頭加上 ID 名選中一個 ID
這個是嚴格匹配的
ID 里面是可以加減號或者是其他符號的
屬性選擇器|attribute selector —— [attr=value]
它包括了 class 屬性選擇器和 id 選擇器
這個選擇器的完整語法就是 attr=value
,等于前面是屬性名,后面是屬性值
這里面的等號前面可以加 ~
就表示像 class 一樣,可以支持拿空格分隔的值的序列:attr~=value
如果在等號前面加單豎線,表示這個屬性以這個值開頭即可:attr|=value
如果我們對優先級沒有特殊要求的話,我們理論上是可以用屬性選擇器來代替 class 選擇器和 id 選擇器的
偽類 —— :hover
以 :
開頭的,它主要是一些屬性的特殊狀態
這個跟我們寫的 HTML 沒有關系,多半來自于交互和效果
一些偽類選擇器是帶有函數的偽類選擇器,這些我們都是可以去使用偽類來解決的
偽元素選擇器 —— ::before
一般來說是以 ::
雙冒號開頭的
實際上是支持使用單冒號的,但是我們提倡雙冒號這個寫法
因為我們可以一眼就看出這個是偽元素選擇器,和偽類區分開來
偽元素屬于選中一些原本不存在的元素
如果我們不選擇它們,這個地方就不存在這個元素了,選擇后就會多了一個元素
復合選擇器
<簡單選擇器><簡單選擇器><簡單選擇器>
* 或則 div 必須寫在最前面
首先復合選擇器是以多個簡單選擇器構成的,只要把簡單選擇器挨著寫就變成一個復合選擇器了。它的語義就是我們選中的元素必須同時 match 幾個簡單選擇器,形成了 “與” 的關系。
復雜選擇器
復合選擇器中間用連接符就可以變成復雜選擇器了,復雜選擇器是針對一個元素的結構來進行選擇的。
<復合選擇器> <復合選擇器> —— 子孫選擇器,單個元素必須要有空格左邊的一個父級節點或者祖先節點
<復合選擇器> “>” <復合選擇器> —— 父子選擇器,必須是元素直接的上級父元素
<復合選擇器> “~” <復合選擇器> —— 鄰接關系選擇器
<復合選擇器> “+” <復合選擇器> —— 鄰接關系選擇器
<復合選擇器> “||” <復合選擇器> —— 雙豎線是 Selector Level 4 才有的,當我們做表格的時候可以選中每一個列
在之前的 《實戰中學習瀏覽器工作原理》中也接觸過選擇器的優先級的概念了。這里我們深入了解一下選擇器優先級的概念。
簡單選擇器計數
我們從一個案例出發,選擇器優先級是對一個選擇器里面包含的所有簡單選擇器進行計數。所以選擇器列表不被視為一個完整的選擇器(也就是逗號分隔的選擇器),因為選擇器列表中間是以逗號分隔開的復雜選擇器來進行簡單選擇器計數的。
例子:
#id div.a#id
這個里面包含了兩個 ID 選擇器,一個類型選擇器和一個 class 選擇器
根據一個 specificity
數組的計數 [inline-style個數
,ID 選擇器個數
,class 選擇器個數
,tagName 選擇器個數
]
我們這個例子就會得出 specificity = [0, 2, 1, 1]
在選擇器的標準里面,有一個這樣的描述,我們會采用一個 N 進制來表示選擇器優先級
所以
我們只需要取一個大的 N,算出來就是選擇器的優先級了
比如說我們用
N=1000000
,那么 S=2000001000001
,這個就是這個例子中選擇器的 specificity
優先級了
像 IE 的老版本 IE6,因為為了節省內存 N 取值不夠大,取了一個 255 為 N 的值,所以就發生了非常好玩的事情,比如說到值我們 256 個 class 就相當于一個 ID。后來我們大部分的瀏覽器都選擇了 65536,基本上就再也沒有發生過超過額度的事情了。因為標準里面只說采用一個比較大的值就可以,但是我們要考慮內存暫用的問題,所以我們會取一個 16 進制上比較整的數,一般來說都是 256 的整次冪(因為 256 是剛好是一個字節)。
偽類其實是一類非常多的內容的簡單選擇器。
鏈接/行為
:any-link
—— 可以匹配任何的超鏈接
:link
—— 還沒有訪問過的超鏈接
:link :visited
—— 匹配所有被訪問過的超鏈接
:hover
—— 用戶鼠標放在元素上之后的狀態,之前是只能對超鏈接生效,但是現在是可以在很多元素中使用了
:active
—— 之前也是只對超鏈接生效的,點擊之后當前的鏈接就會生效
:focus
—— 就是焦點在這個元素中的狀態,一般用于 input 標簽,其實任何可以獲得焦點的元素都可以使用
:target
—— 鏈接到當前的目標,這個不是給超鏈接用的,是給錨點的 a
標簽使用的,就是當前的 HASH指向了當前的 a
標簽的話就會激活 target
偽類
一旦使用了
:link
或者:visited
之后,我們就再也無法對這個元素的文字顏色之外的屬性進行更改。為什么要這樣設計呢?因為一旦我們使用了 layout 相關的屬性,比如說我們給:visited
的尺寸加大一點,它就會影響排班。這樣我們就可以通過 JavaScript 的 API 去獲取這個鏈接是否被訪問過了。但是如果我們能獲得鏈接是否被訪問過了,那么我們就可以知道用戶訪問過那些網站了,這個對于瀏覽器的安全性來說是一個致命打擊。所以這里也提醒一下大家,不要以為做一些表現性的東西于安全沒有任何關系,其實安全性是一個綜合的考量。CSS 它也能造成安全漏洞的。
樹結構
:empty
—— 這個元素是否有子元素
:nth-child()
—— 是父元素的第幾個兒子(child)
:nth-last-child()
—— 于 nth-child
一樣,只不過從后往前數
:first-child :last-child :only-child
:nth-child
是一個非常復雜的偽類,里面支持一種語法,比如說可以在括號里面寫奇偶event
或者odd
,也可以寫4N+1
、3N-1
,這個就會分別匹配到整數的形態。因為這個是一個比較復雜的選擇器,我們就不要在里面寫過于復雜的表達式了,只用它來處理一下奇偶,逢3個多1個,逢4個多1個等等這種表達式。
其實
empty
、nth-last-child
、last-child
、only-child
這兩個選擇器,是破壞了我們之前在 《實現中學習瀏覽器原理》中的說到的 CSS 計算的時機問題。我們可以想象一下,當我們在開始標簽計算的時候,肯定不知道它有沒有子標簽。empty
影響不是特別大,但是last-child
的這個關系其實還是影響蠻大的。所以瀏覽在實現這些的時候是做了特別處理的,要么就是瀏覽器實現的不是特別好,要么就是瀏覽器要耗費更大的性能來得以實現。所以建議大家盡量避免大量使用這些。
邏輯型
:not 偽類 —— 主流瀏覽器只支持簡單選擇器的序列(復合選擇器)我們是沒有辦法在里面寫復雜選擇器的語法的
:where :has —— 在 CSS Level 4 加入了這兩個非常強大了邏輯型偽類
這里還是像溫馨建議一下大家,不建議大家把選擇器寫的過于復雜,我們很多時候都可以多加一點 class 去解決的。如果我們的選擇器寫的過于復雜,某種程度上意味著 HTML 結構寫的不合理。我們不光是為了給瀏覽器工程省麻煩,也不光是為了性能,而是為了我們自身的代碼結構考慮,所以我們不應該出現過于復雜的選擇器。
一共分為 4 種
::before
::after
::first-line
::first-letter
::before
和 ::after
是在元素的內容的前和后,插入一個偽元素。一旦應用了 before 和 after 的屬性,declaration(聲明)里面就可以寫一個叫做 content
的屬性(一般元素是沒有辦法寫 content 的屬性的)。content
的屬性就像一個真正的 DOM 元素一樣,可以去生成盒,可以參與后續的排版和渲染了。所以我們可以給他聲明 border
、background
等這樣的屬性。
可以理解為:偽元素向界面上添加了一個不存在的元素。
::first-line
和 ::first-letter
的機制就不一樣了。這兩個其實原本就存在 content 之中。他們顧名思義就是 選中“第一行” 和選中 “第一個字母”。它們 不是一個不存在的元素,是把一部分的文本括了起來讓我們可以對它進行一些處理。
before 和 after
在我們概念里,我們可以認為帶有 before 偽元素的選擇器,會給他實際選中的元素的內容前面增加了一個元素,我們只需要通過他的 content 屬性為它添加文本內容即可。(這里我們也可以給偽元素賦予 content: ''
為空的)所以我們可以任何的給 before 和 after 指定 display 屬性,和不同元素一樣比較自由的。
我們在實現一些組建的時候,也會常常使用這種不污染 DOM 樹,但是能實際創造視覺效果的方式來給頁面添加一些修飾性的內容。
<div> <::before/> content content content content content content content content content content content content content content content content <::after/> </div>
first-letter 和 first-line
first-letter
相當于我們有一個元素把內容里面的第一個字母給括了起來。這個 first-letter
我們是可以任意聲明各種不同的屬性的,但是我們是無法改變它的 content 的。我們應該都看到過報紙上的第一個字母會比較大,然后會游離出來的效果,這個在 CSS 里面我們就可以用 ::first-letter
的偽元素選擇器了。使用這個來實現相比用 JavaScript 來實現就會更加穩定和代碼更加優雅一些。
<div> <::first-letter>c</::first-letter>ontent content content content content content content content content content content content content content content content </div>
first-line
是針對排版之后的 line
,其實跟我們源碼里面的 first line
沒有任何的關系的。假如說我們的瀏覽器提供的渲染的寬度不同,first-line
在兩個環境里面它最終括住的元素數量就不一樣多了。所以我們用這個選擇器的時候需要去根據需求的情況使用,很有可能在我們開發機器上和用戶的機器上渲染出來的效果是不一樣的!
<div> <::first-line>content content content content content</::first-line> content content content content content content content content content content content content </div>
這兩個選擇器其實可用的屬性也是有區別的:
first-line 可用屬性
font 系列
color 系列
background 系列
word-spacing
letter-spacing
text-decoration
text-transform
line-height
first-letter 可用屬性
font 系列
color 系列
background 系列
text-decoration
text-transform
letter-spacing
word-spacing
line-height
float
vertical-align
盒模型系列:margin, padding, border
編寫一個 match 函數。它接受兩個參數,第一個參數是一個選擇器字符串性質,第二個是一個 HTML 元素。這個元素你可以認為它一定會在一棵 DOM 樹里面。通過選擇器和 DOM 元素來判斷,當前的元素是否能夠匹配到我們的選擇器。(不能使用任何內置的瀏覽器的函數,僅通過 DOM 的 parent 和 children 這些 API,來判斷一個元素是否能夠跟一個選擇器相匹配。)以下是一個調用的例子。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Match Example —— by 三鉆</title> </head> <body> <div> <b> <div class="class classA" id="id">content</div> </b> </div> </body> <script language="javascript"> /** * 匹配選擇器 */ function matchSelectors(selector, element) { // 先匹配當前元素是否匹配 let tagSelector = selector.match(/^[\w]+/gm); let idSelectors = selector.match(/(?<=#)([\w\d\-\_]+)/gm); let classSelectors = selector.match(/(?<=\.)([\w\d\-\_]+)/gm); /** * 實現復合選擇器,實現支持空格的 Class 選擇器 * -------------------------------- */ // 檢查 tag name 是否匹配 if (tagSelector !== null) { if (element.tagName.toLowerCase() !== tagSelector[0]) return false; } // 檢測 id 是否匹配 if (idSelectors !== null) { let attr = element.attributes['id'].value; if (attr) { for (let selector of idSelectors) { if (attr.split(' ').indexOf(selector) === -1) return false; } } } // 檢測 class 是否匹配 if (classSelectors !== null) { let attr = element.attributes['class'].value; if (attr) { for (let selector of classSelectors) { if (attr.split(' ').indexOf(selector) === -1) return false; } } } return true; } /** * 匹配元素 */ function match(selector, element) { if (!selector || !element.attributes) return false; let selectors = selector.split(' ').reverse(); if (!matchSelectors(selectors[0], element)) return false; let curElement = element; let matched = 1; // 遞歸尋找父級元素匹配 while (curElement.parentElement !== null && matched < selectors.length) { curElement = curElement.parentElement; if (matchSelectors(selectors[matched], curElement)) matched++; } // 所有選擇器匹配上為 匹配成功,否則是失敗 if (matched !== selectors.length) return false; return true; } let matchResult = match('div #id.class', document.getElementById('id')); console.log('Match example by 三鉆'); console.log('matchResult', matchResult); </script> </html>
到此,相信大家對“CSS中的選擇器是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。