iT邦幫忙

2021 iThome 鐵人賽

DAY 7
0
Modern Web

後轉前要多久系列 第 7

【後轉前要多久】# Day07 CSS - 打架該聽誰的?CSS權重、繼承

雖然這章節可能有些無聊,遲遲沒進入CSS引人興趣的地方,
但我還是想依我學習時,所想到和納悶的事物按順序一個個講述。

前面介紹了CSS引入的幾種方式,
既然分成這麼多種,就好奇他們彼此之間打架會發生什麼事?
如果設定不同,分歧時到底該優先聽誰的?

CSS 權重 Specificity

前面一章提到了 選取器 Selector,
因為每個選取器都有不同的計分方式,
遇到設定打架時,就聽權重最大的那個人說話!

以下是權重計分由高到低排序:

  1. 最高優先 !important (10000分)
  2. 行內inline style="..." (1000分)
  3. ID選擇器 #id (100分)
  4. 類別選擇器、屬性選擇器 兩者同分 .class[attr=value] (10分)
  5. 標籤選擇器 <tag> (1分)
  6. 通用選取器 * (0分,有其他設定就能蓋掉)

由此高低差異可見,選擇的方式越具體、越有指定性,權重計分就越高。
另外!important 破壞了級聯的比較規則,非不得已時盡量少用。

權重計分分數疊加,ex:

  • .container (10分)
  • .container div (11分)
  • .container .menu div (21分)

例子1:

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="index.css">
</head>
<body>

<p class="class" id="id">
    Lorem ipsum dolor sit amet.
</p>

</div>
</body>
</html>

CSS

*{
    color: aqua;
}

p{
    color: blue;
}

.class{
    color: blueviolet;
}

#id{
    color: red;
}

運行結果是紅色,果真如計分方式那樣,
#id是裡面分數最高的(100分)。
出現紅色不是因為後面設定覆蓋前面設定,而是因為#id權重較大的關係。

例子1運行結果

例子2:

此時將HTML加上一個style行內屬性

...
<p class="class" id="id" style="color: yellow">
    Lorem ipsum dolor sit amet.
</p>
...

style行內樣式是裡面分數最高的(1000分)。
就變黃色(yellow)了,真開心。

例子2運行結果

例子3:

再來將CSS加上一個!important試試

*{
    color: aqua;
}

p{
    color: blue !important;
}

.class{
    color: blueviolet;
}

#id{
    color: red;
}

哇,一下子變成藍色(blue)
果然!important 10000分,無能人擋啊!!

例子3運行結果

例子4:

聽說分數能疊加?
好,那我來試試

在CSS隨手加上幾個!important

*{
    color: aqua;
}

p{
    color: blue !important;
}

.class{
    color: blueviolet !important;
}

#id{
    color: red !important;
}

結果果然是紅色(red)
畢竟拿#id去疊加的分數最高 (10100分)

例子4運行結果

例子5:

!important也可以加在HTML行內!!

HTML

...
<p class="class" id="id" style="color: yellow !important">
    Lorem ipsum dolor sit amet.
</p>
...

哼哼,style行內樣式 加上 !important (11000分)
果然是黃色(yellow)勝出
結果不出所料呢

例子5運行結果


坑 - 權重分數累加?

我們來看看以下的例子

例子6:

HTML

...
<p class="class" id="id">
    Lorem ipsum dolor sit amet.
</p>
...

CSS

.class.class.class.class.class.class.class.class.class.class.class.class.class.class.class{
    color: blueviolet;
}

#id{
    color: red;
}

我把15個.class(10分)累加在一起,分數變成150,
這樣一來能蓋過#id(100分)吧

所以這題會是紫羅蘭色(blueviolet)!!

例子6運行結果

淦,啊出來怎麼會是紅色(red)的?!


權重分數不是單純累加

透過WebStorm IDE的提示可以看到,
確實有吃到15個.class、以及1個#id

WebStorm提示

15個10分的class居然不敵1個100分的id?

沒錯,敵不過。
權重分數的計分並不是單純累加。

我們將分數劃分成五個維度
把上面的計分說明重新修正一下

  1. 最高優先 !important (1|0|0|0|0)分
  2. 行內inline style="..." (0|1|0|0|0)分
  3. ID選擇器 #id (0|0|1|0|0)分
  4. 類別選擇器、屬性選擇器 .class[attr=value] (0|0|0|1|0)分
  5. 標籤選擇器 <tag> (0|0|0|0|1)分
  6. 通用選取器 * (0|0|0|0|0)分

維度相同的權重,計分分數疊加
每個維度互不相干,維度間只存在輾壓的份。

ex:

  • .container (1|0)分
  • .container div (1|1)分
  • .container .menu div (2|1)分

先比較最高維度,相同的話再往低維度比較
多別人一個維度,導致的結果就是輾壓

無論較小的尺寸再多,只要前面存在一個高次元的差距,
分數就是狠狠的輾過去了。

例子7:

HTML

...
<p class="class" id="id">
    Lorem ipsum dolor sit amet.
</p>
...

CSS

#id#id#id.class{
    color: green;
}

#id#id.class.class{
    color: red;
}

回過頭來修改一下CSS,
綠色(3|1|0)前面維度多一個,直接輾壓紅色(2|2|0)

例子7運行結果

所以出來的答案是綠色(green)。

嚴格來說 !important(1|0|0|0|0) 不能列入計分之中,
因為!important是將樣式提升到最高層次,只會出現一次
沒辦法同時出現兩個或多個!important來疊加計分

所以總共只有四個維度的分數(0|0|0|0)


如果有這麼簡單就好了

如果世界如此簡單,網頁就不會這麼複雜了

終於搞懂了權重是怎麼進行比較,
覺得原來如此簡單、世界如此美好、終於可以安穩的睡覺時...

再以權重的角度回頭看看這個例子8:

例子8:

HTML

...
<div class="container" id="c1">
    <div class="content" id="c2">
        <p style="color: red">Lorem ipsum dolor sit amet.</p>
    </div>
</div>
...

CSS

#c1#c1{
    color: green;
}

#c2{
    color: pink !important;
}

嗯,雖然這個c2 pink看來只有一個#id,不敵c1 green的兩個#id
但人家後天努力認真向上,老天賜予他一個!important
這c2一定狠狠屌打c1 green!!
不要不信邪,這ㄍ出來一定是粉紅色辣!!

例子8運行結果

淦~!@#$%^&
怎麼半路跑殺出程咬金,執行結果冒出一個寫在HTML中的紅色(red)?
難道我又被騙惹嗎?


CSS 繼承 Inheritance - 關係的遠近

其實除了權重之外,還要考慮第二件事情,就是繼承。

在CSS中有些屬性是可以往下繼承下去的,如:colorline-heighttext-...
(當然也有只侷限在當前標籤的、不會往下繼承的屬性,如: border)

由於剛剛的例子8中,<p>的style屬性直接選中了<p>標籤作用的位置。

<p style="color: red">Lorem ipsum dolor sit amet.</p>

自己的屬性(直接選用的)優先於繼承來的屬性

所以要先看父子層結構,若均指定在同一層時再比較權重

文章快要結束了、再忍耐一下看看以下的例子9

例子9:

將HTML中的<p>段落拿掉了inline style,
稍加修改一下CSS,
最終出來會是什麼顏色?

HTML

...
<div class="container" id="c1">
    <div class="content" id="c2">
        <p>Lorem ipsum dolor sit amet.</p>
    </div>
</div>
...

CSS

#c1#c1{
    color: green !important;
}

.content{
    color: pink;
}

雖然green有個!important在,看起來分數好像高的嚴重...

例子9運行結果

最終結果出來,
雖然pink分數遠低於!important、甚至比green的兩個#id還要低,
但卻是.class粉紅色(pink)勝出,
原因是目標標籤 離.content描述的標籤關係較近,所以優先繼承他的樣式。


當分數一樣、繼承順序也一樣呢

當分數一樣、繼承順序也一樣的時候,
一定會爆炸了吧?因為根本公平到無法比較了。

不。
此時就會發生後面覆蓋前面設定的狀況。

例子10:

將多個分數一樣(都是class)的樣式,
通通都指定到同一個元素層級(.container)上

HTML

...
<div class="container">
    <style>
        .container{
            color: blue;
        }
    </style>
    <p>Lorem ipsum dolor sit amet.</p>
</div>

<style>
    .container{
        color: yellow;
    }
</style>
...

CSS

.container{
    color: green;
}

.container{
    color: pink;
}

在HTML中最後才出現的<style>黃色(yellow),
默默靜靜地把前面所有人都幹掉了...

例子10運行結果

相同地,如果把<link>連接CSS樣式放在HTML最後面,
則是吃到CSS最後覆蓋的樣式。

<div class="container">
    <style>
        .container{
            color: blue;
        }
    </style>
    <p>Lorem ipsum dolor sit amet.</p>
</div>

<style>
    .container{
        color: yellow;
    }
</style>
<link rel="stylesheet" href="index.css">

吃到的就會是CSS的粉紅色(pink)

把CSS樣式放在HTML最後面

例子11:

在同一個元素中加入多個class,
此時每個class分數、層級都一樣,
後蓋前仍然是以style樣式的順序為主。

...
<style>
    .yellow{
        color: yellow;
    }

    .green{
        color: green;
    }

    .red{
        color: red;
    }
</style>

<div class="red yellow green">
    <p>Lorem ipsum dolor sit amet.</p>
</div>
...

出來是紅色(red)而非綠色(green),
因為red是引用到的樣式之中最後定義的。
相同元素多個class


嗯,看來CSS的陷阱比想像中的還要多...


上一篇
【後轉前要多久】# Day06 CSS - Selectors 選取器
下一篇
【後轉前要多久】# Day08 CSS - CSS Reset
系列文
後轉前要多久30

尚未有邦友留言

立即登入留言