繼承

CSS Podcast - 005:繼承

假設您剛編寫一些 CSS,讓元素看起來像按鈕。

<a href="http://example.com" class="my-button">I am a button link</a>
.my-button {
  display: inline-block;
  padding: 1rem 2rem;
  text-decoration: none;
  background: pink;
  font: inherit;
  text-align: center;
}

然後,在內容文章中新增連結元素,並將 class 值設為 .my-button。不過,文字顏色並非您預期的顏色。為什麼會發生這個問題?

如果您未指定某些 CSS 屬性的值,這些屬性就會繼承值。 就這個按鈕而言,它繼承了這個 CSS 的 color

article a {
  color: maroon;
}

在本課程中,您將瞭解發生這種情況的原因,以及繼承如何成為強大的功能,協助您減少編寫 CSS。

繼承流程

請使用下列 HTML 程式碼片段,瞭解繼承的運作方式:

<html>
  <body>
    <article>
      <p>Lorem ipsum dolor sit amet.</p>
    </article>
  </body>
</html>

根元素 (<html>) 是文件中的第一個元素,因此不會繼承任何項目。 在 HTML 元素上新增一些 CSS,就會開始在文件中層疊。

html {
  color: lightslategray;
}

其他元素預設會繼承 color 屬性。 html 元素具有 color: lightslategray,因此所有可繼承顏色的元素現在都會是 lightslategray 顏色。

body {
  font-size: 1.2em;
}
p {
  font-style: italic;
}

只有 <p> 會顯示斜體文字,因為這是最深層的巢狀元素。 繼承只會向下流動,不會回流至父項元素。

預設會沿用哪些屬性?

根據預設,並非所有 CSS 屬性都會繼承,但有很多屬性會繼承。如需參考,以下是預設會繼承的完整屬性清單,取自所有 CSS 屬性的 W3 參考資料:

繼承的運作方式

根據預設,每個 HTML 元素都會定義每個 CSS 屬性,並提供初始值。 初始值是不會繼承的屬性,如果層疊無法計算該元素的值,就會顯示為預設值。

可繼承的屬性會向下層疊,子項元素會取得代表父項值的計算值。也就是說,如果父項的 font-weight 設為 bold,所有子項元素都會以粗體顯示,除非子項的 font-weight 設為其他值,或使用者代理程式樣式表為該元素設定了 font-weight 值。

如何明確繼承及控管繼承

繼承可能會以意想不到的方式影響元素,因此 CSS 提供相關工具來解決這個問題。

inherit關鍵字

您可以使用 inherit 關鍵字,讓任何屬性繼承父項的計算值。 使用這個關鍵字的好方法是建立例外狀況。

strong {
  font-weight: 900;
}

這個 CSS 程式碼片段會將所有 <strong> 元素的 font-weight 設為 900,而非預設的 bold 值,這相當於 font-weight: 700

.my-component {
  font-weight: 500;
}

.my-component 類別會將 font-weight 設為 500。如要讓 .my-component 內的 <strong> 元素也成為 font-weight: 500,請新增:

.my-component strong {
  font-weight: inherit;
}

現在,.my-component 內的 <strong> 元素會具有 500font-weight

您可以明確設定這個值,但如果您使用 inherit,且 .my-component 的 CSS 日後有所變更,則可確保 <strong> 會自動保持最新狀態。

initial關鍵字

繼承可能會導致元素發生問題,而 initial 則提供強大的重設選項。

您先前已瞭解 CSS 中的每個屬性都有預設值。 initial 關鍵字會將屬性還原為初始預設值。

aside strong {
  font-weight: initial;
}

這段程式碼會從 <aside> 元素內的所有 <strong> 元素移除粗體權重,並改為一般權重 (初始值)。

unset關鍵字

如果屬性預設會繼承,unset 屬性的行為就會有所不同。 如果屬性預設會繼承,unset 關鍵字會與 inherit 相同。如果屬性預設不會沿用,則 unset 關鍵字等於 initial

記住預設會繼承哪些 CSS 屬性可能很困難,這時 unset 就很有幫助。舉例來說,color 預設會繼承,但 margin 不會,因此您可以編寫以下內容:

/* Global color styles for paragraph in authored CSS */
p {
  margin-top: 2em;
  color: goldenrod;
}

/* The p needs to be reset in asides, so you can use unset */
aside p {
  margin: unset;
  color: unset;
}

現在 margin 已移除,color 也還原為繼承的計算值。

您也可以搭配 all 屬性使用 unset 值。 回到先前的例子,如果全域 p 樣式新增了幾個屬性,會發生什麼事?系統只會套用為 margincolor 設定的規則。

/* Global color styles for paragraph in authored CSS */
p {
    margin-top: 2em;
    color: goldenrod;
    padding: 2em;
    border: 1px solid;
}

/* Not all properties are accounted for anymore */
aside p {
    margin: unset;
    color: unset;
}

如果將 aside p 規則改為 all: unset,日後套用至 p 的全域樣式一律會取消設定。

aside p {
    margin: unset;
    color: unset;
    all: unset;
}

revert關鍵字

階層式樣式課程所述,樣式來自不同來源,包括使用者代理程式基本樣式、使用者偏好樣式,以及您撰寫的樣式。revert 關鍵字會還原在 revert 關鍵字使用來源中設定的樣式。

如果您已設定樣式,但不想在某些情況下套用,這項功能就非常實用。inheritinitialunset 會指定如何計算樣式的值,而 revert 只會指定您編寫的其他樣式不適用。

p {
  padding: 2em;
}

aside p {
  padding: revert;
}

這個程式碼片段會為 <p> 元素提供邊框間距,但當 <p> 元素位於 <aside> 內時,完全不會指定 padding。而是會還原為使用者偏好樣式 (如有設定) 或使用者代理程式基本樣式。

revert-layer關鍵字

層疊層可有效整理樣式,並在層疊的作者來源中設定樣式優先順序。revert-layer 關鍵字與 revert 類似,但不會指定屬性不應套用任何作者樣式,只會還原目前層中的樣式。

如果您使用第三方 UI 程式庫,建議將程式庫匯入圖層,並將任何覆寫項目新增至優先順序較高的圖層。接著,您可以使用 revert-layer 移除覆寫,系統就會改用 UI 程式庫的預設值。

如果沒有其他圖層為該屬性指定值,則會像 revert 一樣,使用較早來源的值。

隨堂測驗

測試您對繼承的瞭解程度

下列哪些屬性預設會繼承?

animation
動畫不會傳承給子項。
font-size
🎉
color
🎉
text-align
🎉
line-height
🎉

哪個值的行為類似 inherit,但如果沒有可繼承的項目,則行為類似 initial

reset
無效值,請再試一次!
unset
🎉
superset
無效值,請再試一次!

資源