継承

The CSS Podcast - 005: Inheritance

要素をボタンのように見せる 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-weightbold に設定されている場合、すべての子要素は太字になります。ただし、子要素の font-weight が別の値に設定されている場合や、ユーザー エージェントのスタイルシートにその要素の font-weight の値が設定されている場合は除きます。

継承を明示的に行い、継承を制御する方法

継承は要素に予期しない影響を与える可能性があるため、CSS にはそれを防ぐためのツールが用意されています。

inherit キーワード

inherit キーワードを使用すると、任意のプロパティで親の計算値を継承できます。このキーワードの便利な使い方は、例外を作成することです。

strong {
  font-weight: 900;
}

この CSS スニペットは、すべての <strong> 要素の font-weight を、デフォルトの bold 値(font-weight: 700 と同等)ではなく 900 に設定します。

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

.my-component クラスは、代わりに font-weight500 に設定します。.my-component 内の <strong> 要素も font-weight: 500 にするには、次のように追加します。

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

これで、.my-component 内の <strong> 要素の font-weight500 になります。

この値を明示的に設定することもできますが、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 のように動作し、以前のオリジンの値を使用します。

理解度を確認する

継承に関する知識をテストする

次のプロパティのうち、デフォルトで継承されるものはどれですか?

text-align
color
line-height
animation
font-size

継承するものがなければ inherit のように動作し、その後 initial のように動作する値はどれですか?

unset
reset
superset

リソース