# CSS Specificity > :bookmark:**CSS Specificity( CSS 的權重/優先權):套用在 DOM 上的樣式,互相覆蓋的權力。** > 瀏覽器會通過權重來判斷哪些屬性值與一個元素最為相關,並在該元素上應用這些屬性值。 > 權重是基於不同種類的選擇器 (CSS selectors) 組成的比較規則。 > [color=#f24] **結論**  ## 權重的計算  簡單來說,可以分成四個區塊,從左而右分別是 - inline CSS (例 **style="font-weight:bold"**) - ID selectors (例 **#example**) - Class selectors(例 **.example**)、屬性選擇器(例 **[type="radio"]**)和偽類(例 **:hover**) - Type selectors(例 **h1**)、偽元素(例 **::before**) 這裡可以像 ip 一樣表示成四個數字:0-0-0-0。 這些數字是 CSS 的規則,越往左邊權重越大,而數字越大權重也越大。 > 舉例來說,如果今天樣式表只有寫:div { color:red; },所產生的數字就是:0-0-0-1; > 如果今天寫成:body div div { color:red; },那麼數字就可以表示為:0-0-0-3; > 如果今天寫成:#header div { color:red },那麼數字就要表示為:0-1-0-1; > 而 0-0-0-3 一定會覆蓋過 0-0-0-1 ,0-1-0-1 會覆蓋過 0-0-0-3; > 當然,如果兩個數字完全相同的,就是樣式擺放的比先後順序了。 > [color=#f24] 若還是有點不清楚,可以參考下圖:   ==**權重計算工具**== [Specificity Calculator](https://specificity.keegan.st/) (要注意有些規則會不適用) ## 例外規則 !important ``` css /* 範例: */ table td { height: 50px !important; } ``` > 使用 !important 規則時,將會覆蓋其他的宣告。 > 雖然 !important 與權重無關,但它與最終的結果直接相關。 > 使用 !important 是一個壞習慣,應該盡量避免,因為這破壞了樣式表中的固有的規則,也使得debug變得困難了。 > [color=#f24] 經驗法則: * 一定要優先考慮使用權重來解決問題而不是 !important * 永遠不要在你的套件中使用 !important * 永遠不要在全域的 CSS 代碼中使用 !important 與其使用 !important,你可以: ==1. 更好地利用 CSS 階層屬性== ``` html= <!-- 範例 --> <div id="test"> <span>Text</span> </div> ``` ``` css= /* 範例 */ div#test span { color: green; } div span { color: blue; } span { color: red; } /* 無論 CSS 語句的順序如何,Text 都會是綠色(green), 因為第1行的規則最有針對性、權重最高。 藍色 blue 的規則會覆蓋紅色 red 的規則。 */ ``` ==2. 增加一個或多個其他元素,使 CSS selectors 變得更加具體,並獲得更高的權重。== ``` css= /* 範例 */ #myId#myId span { color: yellow; } .myClass.myClass span { color: orange; } ``` ### 什麼的情況下可以使用 !important: **1. 覆蓋 inline CSS** 假設你的網站上有一個設定了全域的 CSS 文件,同時你(或是你同事)寫了一些很差的 inline CSS。 inline CSS 和 !important 都被認為是非常不好的做法,但是有時你可以在CSS文件裡用!important去覆蓋 inline CSS。 在這種情況下,你就可以在你全域的 CSS 文件中寫一些 !important 的樣式來覆蓋掉那些inline CSS。 ``` html= <div class="foo" style="color: red;">What color am I?</div> ``` ``` css= .foo[style*="color: red"] { color: firebrick !important; } ``` **2. 覆蓋權重高的選擇器** ``` css= /* 如果不使用 !important ,第一條規則永遠比第二條的權重更高 */ #someElement p { color: blue; } p.awesome { color: red; } ``` 讓上述例子的第二條規則 權重變高的方法 :arrow_down: ``` css= /* 直接用 !important */ #someElement p { color: blue; } p.awesome { color: red !important; } /*////////////////////////*/ /* 也可以改寫原來的規則,以避免使用 !important */ [id="someElement"] p { color: blue; } p.awesome { color: red; } ``` ## 一些特別的偽類的計算方式 ### :is() 和 :not() 有例外規則 :is() 和 :not() 在權重計算中不會被看作是偽類( pseudo-class )。 事實上,在計算選擇器數量時還是會把其中的選擇器當做 Type selectors 進行計數。 ``` html= <div class="outer"> <p>This is in the outer div.</p> <div class="inner"> <p>This text is in the inner div.</p> </div> </div> ``` ``` css= div.outer p { color: orange; } div:not(.outer) p { color: blueviolet; } ``` 結果:  ### :where() 有例外規則 :where()會將自己的權重替換成 0。 ``` html= <div class="outer"> <p>This is in the outer div.</p> <div class="inner"> <p>This text is in the inner div.</p> </div> </div> ``` ``` css= div:where(.outer) p { color: orange; } div p { color: blueviolet; } ``` 結果:  ## 基於形式的權重(Form-based specificity) 權重是基於選擇器的形式進行計算的。 在下面的例子中,儘管選擇器*[id="foo"]選擇了一個ID, 但它還是作為一個屬性選擇器來計算自身的權重。 ``` html= <p id="foo">I am a sample text.</p> ``` ``` css= *#foo { color: green; } *[id="foo"] { color: purple; } ``` 結果:  ## 無視 DOM 樹中的距離 ``` html= <html> <body> <h1>Here is a title!</h1> </body> </html> ``` ``` css= body h1 { color: green; } html h1 { color: purple; } ``` 結果:  ## 直接添加樣式 vs. 繼承樣式 為目標元素直接添加樣式,永遠比繼承樣式的權重高,無視權重的遺傳規則。 ``` html= <html> <body id="parent"> <h1>Here is a title!</h1> </body> </html> ``` ``` css= #parent { color: green; } h1 { color: purple; } ``` 結果:  因為 h1 選擇器明確的定位到了元素,但綠色選擇器的僅僅繼承自其父級。 --- ## [補充] ::before 和 ::after ::: info **偽元素 (pseudo-element)** 什麼是「偽元素」? 1. 「偽元素」之所以稱作「偽」,除了英文從「Pseudo」翻譯過來之外,就是因為它並不是真正網頁裡的元素,但行為與表現又和真正網頁元素一樣,也可以對其使用 CSS 操控。 2. 跟偽元素類似的還有「偽類」( Pseudo classes ),在 W3C 的定義裡總共有五個偽元素 ( 其他仍在測試階段 )分別是 ::before、::after、::first-line、::first-letter和::selection。 3. 為了和偽類區分,偽元素使用兩個冒號「::」開頭,而偽類使用一個冒號「:」開頭 ( 像是 :hover、:target...等 )。 4. 雖然現在的瀏覽器就算寫一個冒號也可以正常運作,為了方便區分,用兩個冒號還是比較好, 且不論瀏覽器是什麼,::selection必須是兩個冒號才能正常運作。 ::: ### ::before (:before) * ::before 創建一個偽元素,作為已選中元素的元素的第一個子元素。 * ==必須用 content 屬性來為一個元素添加修飾性的內容。== * 此元素默認為行內元素 (display:inline-block) 的屬性存在。 ### ::after(:after) * ::after 用來創建一個偽元素,作為已選中元素的最後一個子元素。 * 同 ::before 的特點。 語法範例: ``` css /* CSS3 語法 */ /* Add a heart before links */ a::before { content: "♥"; /* (單冒號)CSS2 過時語法 (僅用來支持 IE8) */ element:before { 樣式 } /* 在每一個p元素前插入內容 */ p::before { content: "Hello world!"; } } ``` 實例: ```html= <div>大家好,我是 div</div> ``` ```css= div::before{ content:"我是 before"; color:red; } div::after{ content:"我是 after"; color:red; } ``` 結果:  ### 實用的 content 1. 需要注意使用上一定要具備 content 的屬性,就算是只有 content:""。 2. 沒有 content 的偽元素不會出現在畫面上。 3. content 是個很特別的屬性,它可以使用 attr 直接獲取內容元素的屬性值 ( attribute )。 * 舉例來說,在 HTML 裡有一個超連結,點擊後會彈出新視窗並連結至 Google: ``` html <a href="https://www.google.com" target="_blank">google</a> ``` * 使用下列的用法,將會把超連結的 href 內容與 target 內容,透過偽元素一前一後的顯示出來。 ``` css= a::before{ content: attr(href); color:red; } a::after{ content: attr(target); color:green; } ```  * content 內容是可以「相加」的,不過用法不像 JavaScript 使用 + 號來相連,而是直接用一個空白鍵就可以不斷的累加下去。 ``` css= a::before{ content: "( " attr(href) " ) < "; color:red; } a::after{ content: " > ( " attr(target) " ) "; color:green; } ```  * content 也可以使用 url 放入圖片的功能。 ```css= div::before{ content:url(圖片網址) url(圖片網址) url(圖片網址); } ```  **總結:** 雖然偽元素很好用,但偽元素的內容實際上不存在網頁裡 ( 如果打開瀏覽器的開發者工具,會看不到內容 ),所以如果在裡頭塞了太多的重要的內容,反而會影響到 SEO 的成效。 因此對於使用偽元素的定位,還是當作「輔助」性質會比較恰當。 --- **筆記引用資料:** [CSS Specificity MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) [CSS Specificity - OXXO.STUDIO](https://www.oxxostudio.tw/articles/201405/css-specificity.html) [CSS 偽元素 ( before 與 after ) - OXXO.STUDIO](https://www.oxxostudio.tw/articles/201706/pseudo-element-1.html)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up