一.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 {}
這就體現了組合偽類語義明確的優勢
暫無評論,快來發表你的看法吧