注意
この記事はAIのアシスタントによって翻訳・編集されています。
目次
- 1. 問題:なぜボタンの文字色がマルーンになるのか?
- 2. 本質:CSSにおける継承の仕組み
- 3. 継承を制御する5つのグローバルキーワード
- 4.
all: 全プロパティを一括リセット(注意点付き) - 5. computed value(計算値) — 継承が実際に行われる場所
- 6.
emとrem– 継承そのものではないが密接に関連する - 7. React + TypeScript での実践例
- 8. CSS変数 – 継承される?されない?
- 9. パフォーマンスと継承
- 10. 実践チェックリスト
- 11. まとめ
- 12. 参考資料
- 次回予告
1. 問題:なぜボタンの文字色がマルーンになるのか?
次のようなコードを考えてみましょう。
<div class="article">
<p>
これはテキストです。
<a class="btn" href="#">登録する</a>
</p>
</div>
.article {
color: maroon;
}
.btn {
background: blue;
padding: 8px 16px;
/* color は指定していない */
}
ボタンの文字色は何色になるでしょうか?
答えは マルーン です。.btn に color を指定していないため、親要素 .article の color: maroon が 継承 されるからです。
(補足:上記の例では <button> ではなく <a> タグを使っています。ブラウザのUAスタイルシートがボタンの color を上書きする可能性を避けるためです。あくまで継承の仕組みを説明するためのシンプルな例です。)
🤔 font-family と background はどちらもCSSプロパティなのに、なぜ一方は自動的に子孫に伝わり、もう一方は伝わらないのでしょうか?
この記事では CSS の継承の仕組みを整理しながら、inherit・unset・revert の違いについて解説します。
2. 本質:CSSにおける継承の仕組み
CSS の各プロパティは、継承プロパティと非継承プロパティのどちらかに分類されます。
なぜ font-family は継承されるのか?
-
font-familyはテキストの内容に関わるからです。 - インターフェースデザインでは、フォントの一貫性が当然求められます。子孫も特に指定がなければ同じフォントを使うべきです。
- 同じスタイルを繰り返し記述する必要がなくなります。
なぜ background は継承されないのか?
-
backgroundは要素のボックスと表示領域に関わるからです。 - もし背景が継承されたら、青色の背景を持つセクションの中のすべての子要素も青色の背景を持つことになります。これは不要な繰り返しであり、要素ごとの見た目の区別がつきにくくなります。
よく継承されるプロパティの例:
-
color,font-family,font-size,font-weight,line-height -
text-align,letter-spacing,word-spacing -
visibility,white-space,cursor
開発者が「えっ、これも継承されるの?」と驚くプロパティたち:
cursorvisibilitytext-transformlist-stylequotes
例えば:<div class="card"> に cursor: pointer を設定すると、内部の <span> も cursor を再宣言しなくてもポインターになります。cursor は継承プロパティだからです。
継承されない代表的なプロパティ:
-
background,border,margin,padding -
width,height,box-sizing,display -
position,top,left,right,bottom
3. 継承を制御する5つのグローバルキーワード
CSSには、継承の仕組みを制御するための5つのグローバルキーワード (CSS-wide keywords) が用意されています。
-
inherit– プロパティが通常継承されるかどうかに関わらず、親から値を強制的に継承します。非継承プロパティを親と揃えたい場合に便利です。 -
initial– プロパティを CSS仕様で定義された初期値 (initial value) に戻します。ブラウザのデフォルトスタイルではありません。例えばdisplay: initialはinlineになりますが、ブラウザのUAスタイルシートではdivはblockになっています。 -
unset– 継承プロパティならinheritと同じ動作、非継承プロパティならinitialと同じ動作をします。「スマートリセット」 として最も安全な選択肢です。 -
revert– 現在のオリジン (作者スタイルシート) の値を破棄し、カスケードでより低いオリジン (ユーザースタイルシート or UAスタイルシート) の値に戻します。必ずしもUAスタイルシートに戻るとは限りません。 -
revert-layer(Cascade Level 5+、2022年以降サポート) – 同じオリジン内でのみロールバックし、@layerで定義された前のレイヤーの値に戻します。
5つのキーワード比較表
詳細:
| キーワード | 継承プロパティでの動作 | 非継承プロパティでの動作 | 備考 |
|---|---|---|---|
inherit |
親から値を継承 | 親から値を継承 | 非継承プロパティでも強制的に継承させる |
initial |
仕様の初期値 | 仕様の初期値 | ブラウザのデフォルトではないことに注意 |
unset |
親から値を継承 | 仕様の初期値 | 「スマートリセット」 – 最も安全 |
revert |
ユーザー/UAオリジンへ戻す | ユーザー/UAオリジンへ戻す | 作者スタイルを完全に無視 |
revert-layer |
同じオリジン内の前のレイヤーへ戻す | 同じオリジン内の前のレイヤーへ戻す |
@layer を使っている場合に有効 |
4. all: 全プロパティを一括リセット(注意点付き)
要素のすべてのプロパティを一度にリセットしたい場合は、all キーワードを使います。値には initial, inherit, unset, revert, revert-layer が指定できます。
.card {
all: unset; /* すべてのプロパティを unset のルールに従ってリセット */
/* その後、必要なスタイルを再定義 */
display: block;
padding: 1rem;
border-radius: 8px;
}
all は unicode-bidi、direction、CSSカスタムプロパティには影響しません。
all: unset は強力ですが、特に button、input、select、textarea などのインタラクティブ要素では注意して使う必要があります。リセットによって以下のような重要なデフォルト動作が失われる可能性があります:
- デフォルトの
display値 (ボタンは本来inline-block) - フォントの継承
-
appearanceやブラウザのデフォルトスタイル - フォーカススタイルやアクセシビリティ関連の動作 (例: フォーカス時のアウトライン)
-
:active、:disabledなどの状態のデフォルト動作
重要な注意: color や font-family のような継承プロパティに対して、all: unset はそれらをブラウザのデフォルト値に戻すのではなく、引き続き親から継承します。この点は非常に多くの人が誤解しています。
インタラクティブ要素に all: unset を使う場合は、アクセシビリティに必要なスタイルを必ず復元してください。
5. computed value(計算値) — 継承が実際に行われる場所
「継承とは子要素が親から値をもらうこと」と理解している人は多いですが、実際には computed value(計算値) と呼ばれる中間ステップで発生します。
ブラウザはCSSの値を次のように処理します:
指定値 (specified value) – 宣言された値、または継承された値
↓
カスケード値 (cascaded value) – カスケード後
↓
計算値 (computed value) – 継承の解決、相対単位→絶対単位への変換など
↓
使用値 (used value) – レイアウト後
↓
実効値 (actual value) – 丸め、制限など
継承プロパティの場合、ブラウザは親要素の computed value を基にして子要素の値を決定します。 このことを理解しておくと、例えば em がどのように計算されるかといった複雑な動作も把握しやすくなります。
6. em と rem – 継承そのものではないが密接に関連する
em は継承とは異なる仕組みですが、親要素の font-size を基準に計算されます。
例:
.parent {
font-size: 20px;
}
.child {
font-size: 2em; /* 親のフォントサイズの2倍 */
}
結果:.child の font-size は 40px になります。これは継承ではありません(子は 20px を受け取っているわけではないからです)。これは相対値の解決 (relative value resolution) と呼ばれるもので、親の computed value を参照して新しい値を算出しています。
一方、rem はルート要素 (<html>) の font-size を基準にするため、中間の親要素の影響を受けません。
em をネストすると「フォントサイズが倍々になる」問題を避けるためにも、この違いを理解しておくことが重要です。
7. React + TypeScript での実践例
例1: 親から color を継承してしまうボタン
問題: ボタンに color が宣言されていないため、.article から color: maroon を継承してしまう。
// Article.tsx
import React from 'react';
import './Article.css';
export const Article = ({ children }: { children: React.ReactNode }) => {
return <div className="article">{children}</div>;
};
/* Article.css */
.article {
color: maroon;
font-family: Georgia, serif;
}
// LinkButton.tsx (UAスタイルシートの影響を避けるため <a> を使用)
import React from 'react';
interface LinkButtonProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
variant?: 'primary' | 'secondary';
}
export const LinkButton: React.FC<LinkButtonProps> = ({ children, variant = 'primary', className, ...props }) => {
return (
<a className={`btn btn-${variant} ${className || ''}`} {...props}>
{children}
</a>
);
};
/* Button.css */
.btn {
background: #0066cc;
padding: 8px 16px;
border-radius: 4px;
display: inline-block;
text-decoration: none;
}
.btn-primary {
/* color なし → 継承される */
}
結果: ボタンの文字色はマルーンになる。
解決策: .btn または .btn-primary に color を直接宣言する。
.btn {
color: white;
background: #0066cc;
/* ... */
}
「継承された値は、特異度で子要素のセレクタと競合する」と誤解する人が多いですが、実際は違います。子要素に直接宣言された値は、親セレクタの特異度に関係なく、常に継承された値に勝ちます。 子要素にそのプロパティの宣言がまったくない場合にのみ、継承された値が使われます。
例2: unset を使ってコンポーネントのレイアウトをリセット
// Card.tsx
import React from 'react';
import './Card.css';
export const Card: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return <div className="card">{children}</div>;
};
/* Card.css */
.card {
all: unset; /* すべてのプロパティを unset のルールでリセット */
display: block;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 16px;
}
例3: all: unset – インタラクティブ要素では注意
ボタンをグローバルCSSの影響から完全に切り離したい場合、all: unset が使えますが、必要なスタイルは必ず復元しなければなりません。
// ResetButton.tsx
import React from 'react';
import './ResetButton.css';
export const ResetButton: React.FC<{ onClick: () => void; children: React.ReactNode }> = ({ onClick, children }) => {
return (
<button className="reset-btn" onClick={onClick}>
{children}
</button>
);
};
/* ResetButton.css */
.reset-btn {
all: unset;
/* 必須:デフォルトの動作を復元 */
display: inline-block; /* ボタンのデフォルトは inline-block */
cursor: pointer;
background: #0066cc;
color: white;
padding: 8px 16px;
border-radius: 4px;
}
.reset-btn:focus-visible {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
.reset-btn:active {
transform: scale(0.98);
}
8. CSS変数 – 継承される?されない?
CSS変数 (カスタムプロパティ) は通常のCSSプロパティとは異なり、デフォルトで継承されます。
:root {
--primary-color: #3498db;
}
.card {
--primary-color: #e74c3c; /* このコンポーネント内で上書き */
}
button {
background: var(--primary-color); /* 最も近いスコープの値が使われる */
}
ただし、@property を使うと継承の有無を制御できます。
@property --primary-color {
syntax: '<color>';
inherits: false; /* 継承させない */
initial-value: #3498db;
}
9. パフォーマンスと継承
「継承はブラウザを遅くする」という誤解がたまにあります。実際には、継承は computed value の段階で処理されるため、レイアウトやペイントの前に完了します。パフォーマンスへの影響はごくわずかです。
実際にパフォーマンスへ影響しやすいのは次のような処理です。
- リフロー (reflow) – レイアウト変更 (width, height, margin, padding など)
- リペイント (repaint) – 見た目の変更 (color, background, box-shadow など)
- セレクタマッチング – 複雑すぎるセレクタ
継承は記述するCSSの量を減らし、通常はパフォーマンスに悪影響を及ぼしません。
たとえプロパティが何段階もの親から継承されていても、ブラウザはレンダリングのたびにDOMツリーを遡って値を探すようなことはしません。継承された値は内部データ構造に保持され、効率的に伝達されます。
10. 実践チェックリスト
- □ そのプロパティが継承対象か確認したか
- □ スタイルリセットには
initialではなくunsetを使っているか - □ 継承を上書きするために
!importantを濫用していないか(直接宣言で十分) - □ CSS変数の継承を理解し、テーマシステムに活用しているか
- □
all: unsetを使う場合、アクセシビリティとデフォルト動作を復元しているか - □ DevTools で computed styles を確認し、継承の問題をデバッグしたか
- □
initialはブラウザデフォルトではなく仕様上の初期値であることを理解しているか - □
revertは必ずしもUAスタイルシートに戻るわけではない(ユーザースタイルシートの可能性もある) - □
emとremの違い、特に継承・相対値解決との関係を理解しているか
11. まとめ
- すべてのCSSプロパティは「継承プロパティ」か「非継承プロパティ」のいずれかです。
- テキスト関連のプロパティ (typography, color など) は通常継承されます – コードを簡潔で一貫性のあるものにします。
- レイアウトやボックスモデルに関わるプロパティは通常継承されません – 意図しないスタイルの伝播を防ぎます。
- 5つのグローバルキーワード (
inherit,initial,unset,revert,revert-layer) を使いこなすことで継承を自在に制御できます。 unsetは「スマートリセット」として最も安全な選択肢です。allを使うと全プロパティを一度にリセットできますが、インタラクティブ要素では特に注意が必要です。- CSS変数はデフォルトで継承されますが、
@propertyで制御できます。 - 継承の実際の処理は computed value の段階で行われます。
emは継承そのものではなく「相対値解決」ですが、継承と一緒に語られることが多い重要な概念です。
12. 参考資料
- MDN: 継承
- MDN: CSS全体キーワード (inherit, initial, unset, revert, revert-layer)
- MDN: all
- MDN: CSSカスタムプロパティの使用
- web.dev: 継承
- CSS Cascade Level 5 仕様
- CSS Values and Units Level 4 – computed value
次回予告
👉 【Frontend CSS – パート4】なぜ width: 100% なのにはみ出るのか?Box Model と box-sizing を理解する
