超鏈接的lvha原則

一.lvha
實際上應該是lvfha,即:


a:link {/* 未訪問過的超鏈接的樣式 */}
a:visited {/* 訪問過的超鏈接的樣式 */}
a:focus {/* 擁有焦點的超鏈接的樣式 */}
a:hover {/* 鼠標懸停的超鏈接的樣式 */}
a:active {/* 被用戶輸入激活的超鏈接的樣式 */}

這5個都是僞類,表示5種狀態,其中link與visited是超鏈接專用的,可以分類到鏈接僞類,而focus,hover和active除了用於超鏈接還適用於其它元素,稱爲動態僞類

lvfha原則是說對超鏈接(帶href屬性的a標籤)應用上面的5個僞類時,應該遵守這種固定的順序

二.僞類與僞元素
僞類像類一樣,用來選擇DOM樹上本就存在的某個元素。選擇條件有兩種:

狀態:元素是否處於某種特定狀態,例如用戶曾訪問過(link/visited),此刻擁有焦點(focus),處於某種語言環境(lang)

結構:元素是否滿足某種DOM結構方面的要求,例如身爲長子的元素(first-child),以及CSS3新增的身爲根元素的元素(root)和一大堆的結構化僞類(nth--of-type等等)

僞元素更像元素一些,用來選擇DOM樹上本不存在的元素(或某個元素的一部分)。比起僞類的繁榮大家族,僞元素就顯得有些伶仃了,到目前(2017/11/4)爲止,CSS3規範中仍然只有4個僞元素(CSS2.1就是4個):

首字母:選擇元素包含的文本內容的首字母(文本內容包含來自子元素的,也就是說可以跨標籤層級選擇文本)

首行:選擇元素包含的文本內容的首行(同上)

before:用於內容生成,在指定元素內容開頭的位置生成一個元素(生成的內容位於元素內容區裏)

after:用於內容生成,在指定元素內容結尾的位置生成一個元素(同上)

僞類與僞元素最大的區別是要選擇的目標內容是否存在於DOM上,存在就是僞類,不存在就屬於僞元素。換個角度看,想要爲文檔的某部分內容指定樣式,那麼先要(通過選擇器)選中這部分內容,此時會遇到兩種情況:

目標內容恰好被某個標籤包起來了,對這整個標籤設置樣式就能達到目的

目標內容前後沒有標籤圈定範圍,無法直接設置樣式,需要插入一個臨時標籤把目標內容圈起來,再對這個臨時標籤設置樣式

第一種情況通過僞類來處理,用僞類選擇器把處於某種狀態或具有某些結構特徵的現有元素找出來,再應用樣式。第二種情況要麼手動插入額外標籤,轉化成第一種情況(有些場景通過添標籤也做不到,比如首行,或者跨標籤層級的場景),要麼通過僞元素來解決,相當於請瀏覽器幫忙插入虛擬標籤圈定目標內容,再應用樣式

P.S.關於CSS3選擇器的更多信息,請查看CSS選擇器分類總結

三.a標籤的6種狀態
lvfha僞類給超鏈接提供了5種狀態,第6種是指錨點,而不是超鏈接

link僞類存在的意義之一就是把超鏈接與錨點區分開,link僞類只匹配具有href的a標籤(即超鏈接),而非錨點

一般桌面瀏覽器環境下,a標籤的6種狀態及對應的觸發行爲分別是:


a {/* 處於任意狀態的a標籤,不論是超鏈接還是錨點 */}
a:link {/* 未訪問過的超鏈接 */}
a:visited {/* 訪問過的超鏈接,點擊超鏈接再返回當前頁,這個超鏈接就處於visited狀態 */}
a:focus {/* 獲得焦點的超鏈接,tab鍵選中超鏈接或者長按超鏈接再移開鼠標 */}
a:hover {/* 鼠標懸停的超鏈接,鼠標經過超鏈接時或懸停在超鏈接上時,這個超鏈接就處於hover狀態 */}
a:active {/* 處於激活狀態的超鏈接,鼠標在超鏈接上按下時 */}

其中focus, hover, active不太好區分,focus是一種延續性狀態,而hover, active是短暫性狀態,進一步細分hover, active的話,後者是前者的一種特殊狀態(觸摸設備除外),例如:


a:focus {border: 1px solid green;}
a:hover {border-color: red;}
a:active {border-style: dashed;}

那麼下列連續操作對應的狀態和樣式分別是:


按下tab鍵 -> focus -> 綠色實線邊框
點擊其它空白處 -> a & link | visited -> 對應樣式
鼠標劃過時 -> hover -> 無邊框
鼠標懸停時 -> hover -> 無邊框
鼠標按下 -> focus & hover & active -> 紅色虛線邊框
鼠標移到超鏈接之外再擡起 -> focus -> 綠色實線邊框
(不點擊其它地方的話,超鏈接將一直處於focus狀態)
鼠標劃過時 -> focus & hover -> 紅色實線邊框

正因爲focus是一種延續性狀態,所以要放在短暫性的hover, active之前,否則最後鼠標劃過時不會表現出hover樣式(根據層疊規則,先聲明的hover會被focus覆蓋掉)

因爲focus, hover, active3個狀態有重疊,所以建議保持特定的聲明順序,讓層疊結果符合樣式表編寫者的預期。而link和visited是互斥的,不存在重疊,所以二者的相對順序並不重要(vlfha也是合理的,“愛恨”順序只是好記)。同樣,由於link/visited是永久性狀態,爲了讓短暫性狀態和持續性狀態有表現機會,就把focus/hover/active放在後面,讓長狀態的層疊優先級更低一些,所以就有了lvfha原則

另外,規範沒有明確說明focus, hover, active對應的狀態的起止條件:

CSS沒有定義哪些元素可以處於上面的狀態,以及這些狀態怎樣進入和離開。腳本可以改變元素是否對用戶事件做出響應,並且不同的設備和UA指向和激活元素的方式不同

CSS 2.1沒有定義如果一個’:active’或者’:hover’元素的父級是不是也處於這種狀態

(摘自5.11.3 動態僞類: :hover,:active與:focus)

所以不能確定動態僞類的觸發行爲,也無法確定這幾個僞類適用於哪些元素(表單元素、div等可能支持也可能不支持),都取決於用戶代理的實現

四.組合僞類
建議遵循lvfha順序是考慮層疊規則,否則可能會被覆蓋,導致同名規則無效。例如:


a:hover {text-decoration: underline overline;}
a:link {text-decoration: none;}
a:visited {text-decoration: none;}

hover樣式(小技巧:鼠標劃過時同時顯示上劃線和下劃線)永遠不會生效,因爲text-decoration屬性總會被下面兩條之一覆蓋掉

當然,前提條件是樣式規則存在衝突(同名屬性且來源、重要性、特殊性都相同)時,根據聲明順序來解決衝突,此時lvfha順序才真正起作用。換句話說,如果不存在樣式衝突,聲明順序並不重要

也就是說,通過其他方式避免樣式衝突發生,就不用遵守lvfha順序了,例如通過組合僞類來把狀態展開:


/* 不要求順序 */
:link
:visited
:link:hover
:visited:hover
/* 要求順序 位於上2行之後 */
:link:active
:visited:active
/* 或者替掉上2行 不要求順序 */
:link:hover:active
:visited:hover:active

展開之後就沒有重疊狀態了,讓每條規則都變成嚴格互斥的,自然就沒衝突了

P.S.注意:因爲IE6-不能正確處理組合僞類,只認最後一個,所以lvha應用更廣(實際上組合僞類的語義更明確,沒有“隱藏的奇怪規則”)

另外,可以層疊規則來實現特殊效果,例如:


// 用lhva實現只有未訪問的鏈接纔有hover效果
a:link {}
a:hover {}
a:visited {}
a:active {}

很有意思的小技巧,相當於:


a:link:hover {}

這就體現了組合僞類語義明確的優勢

聯繫ayqy

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章