HTML & CSS / Foundations / Lesson 5
Selectors, inheritance, and the cascade
Predict which declarations apply by separating matching, precedence, specificity, and inheritance.
On this page
Lesson goals
- Match the intended elements
- Compare specificity in its proper context
- Debug from evidence instead of force
Match the intended elements
A CSS rule pairs a selector with declarations. Type selectors match element names, class selectors match reusable class tokens, and id selectors match an identifier that should be unique in the document. Combinators express relationships: a descendant selector reaches any depth, while > requires a direct child. A selector that matches nothing cannot affect the page regardless of its specificity. Check the live DOM and spelling before escalating a selector. Classes are often a practical styling contract because they avoid tying appearance to a deeply nested document structure that can change during content edits.
Read declarations independently
Each property declaration is evaluated under its own grammar and cascade. A missing semicolon between declarations can damage parsing; a valid but unsupported property may be ignored. A later valid declaration can provide a fallback when an earlier or later candidate is unavailable, but order must match the intended enhancement. Developer tools show crossed-out declarations, invalid values, and rules disabled by media conditions. These states have different causes. Avoid interpreting every crossed-out value as a specificity problem: it may lose to an origin, layer, important declaration, or a value from an active transition instead.
Compare specificity in its proper context
Specificity compares matching selectors only after earlier cascade decisions put their declarations in the same competition. In an ordinary unlayered author example without !important, an id selector outranks a class selector, which outranks a type selector. Equal specificity then uses the relevant later tie-breaks, commonly source order when no scope proximity differs. The first example deliberately stays in that simple context so the title becomes dark red. It does not establish a universal claim that an id wins against user important styles, layers, transitions, or every inline declaration. Teach the limited example and the larger algorithm separately.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Specificity experiment</title>
<style>
h1 { color: navy; }
.title { color: green; }
#topic { color: #8b0000; }
</style>
</head>
<body>
<main><h1 id="topic" class="title">Cascade experiment</h1></main>
</body>
</html>
The heading color is #8b0000.
All three rules match in the same ordinary author context. The id selector wins the color comparison; other properties retain their own cascade results.
Inheritance is a different mechanism
Some properties, including color and font-family, normally inherit from the parent when the element has no winning value of its own. Others, such as margin and border, do not inherit by default. An inherited value does not compete as though its ancestor’s selector matched the child. The second example sets a container color, then directly colors one child, showing that direct declarations control that child’s property. Use inherit, initial, unset, or revert only after understanding their distinct meanings; these keywords do not all mean “undo my last rule.” Shorthand properties can reset related longhands unexpectedly.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Inheritance experiment</title>
<style>
.notice { color: #174a28; }
.special { color: #7a163a; }
</style>
</head>
<body>
<main class="notice"><h1>Inherited colors</h1><p>Ordinary paragraph.</p><p class="special">Directly colored paragraph.</p></main>
</body>
</html>
Ordinary text inherits #174a28; the special paragraph uses #7a163a.
The heading and ordinary paragraph inherit green. The special paragraph has its own declaration and becomes the specified burgundy.
Debug from evidence instead of force
Start with whether the stylesheet loaded, then whether the selector matches, whether its conditions apply, whether the value is valid, and which declaration wins. Inspect the computed property and the box it affects. Adding !important before answering those questions makes future maintenance harder and may conceal a wrong target. Keep component selectors modest, use a documented order, and isolate third-party styles through architecture when needed. Later lessons introduce layers as an explicit ordering tool. A reliable fix explains why one declaration wins rather than relying on a selector that merely looks more intimidating.
Common errors and fixes
A rule never affects its intended element
- Why it happens
- The selector does not match the actual DOM.
- How to fix it
- Inspect the element and correct its class or relationship.
- Prevent it next time
- Verify matching before comparing specificity.
A child ignores a parent’s complex color rule
- Why it happens
- The child has its own winning declaration.
- How to fix it
- Inspect the child’s direct styles separately from inherited values.
- Prevent it next time
- Do not treat inheritance as selector competition.
Overrides accumulate !important everywhere
- Why it happens
- The underlying cascade order was never designed.
- How to fix it
- Remove unnecessary force and define clear ownership and ordering.
- Prevent it next time
- Review the cause of each override.
Check your understanding
1. Two class selectors set the same property in the same layer and scope. What decides an otherwise equal conflict?
Show worked solution
After confirming matching, importance, origin, layer, and equal specificity and scope proximity, the later applicable declaration wins by source order. The ordering is a tie-break under those conditions, not a rule that every later stylesheet declaration beats every earlier one.
2. Why can setting color on a parent fail to change one nested button?
Show worked solution
The button can have a direct color declaration from browser or author styles, so it need not inherit the parent’s color. Inspect its computed color and winning rule, then deliberately use color: inherit where that behavior fits the component’s contrast and state requirements.
Key takeaways
- Matching precedes specificity.
- The cascade has several ordered decisions.
- Inherited values differ from direct declarations.