Command Palette

Search for a command to run...

Hectal
PHASE 2Beginner ~22 min· topic 3 of 5

Topic 2.3

Inheritance

In one line

Some properties, mostly about text such as color and font, pass from a parent element to its children automatically; the rest do not. The keywords inherit, initial, unset and revert let you control this on purpose.

Think of it like this

A family. Children often inherit their parents' language and accent without anyone teaching them each word. But they don't inherit their parents' coats: each child gets their own. In CSS, text-related properties like color and font-family are like the language (passed down), and box-related properties like border and padding are like the coats (each element has its own).

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Parent and child
An element directly inside another is its child; the outer one is its parent.
Inheritance
When an element takes a property's value from its parent because no rule set it.
Inherited property
A property that passes down by default, like color or font-family.
Initial value
The built-in default value the CSS specification gives each property, like transparent for background-color.
Computed value
A value after the browser has worked out relative units, like 2em becoming 32px.
inherit
A keyword that forces an element to use its parent's value for a property.
initial
A keyword that resets a property to the specification's initial value.
unset
A keyword meaning "as if no rule set this": inherit if the property is inherited, otherwise initial.
revert
A keyword that rolls a property back to the browser's default style for that element.

Step by step

01Set text styles once, on the body

Because color, font-family and line-height are inherited, one rule on body styles the whole page's text. Every element that doesn't set them itself takes them from its parent, which took them from its parent, all the way up.

style.csswhole filecss
body {
  color: #222;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
}
Set text styles once, on the bodydiagram
Rendering diagram…

02Notice what does not flow down

Add border: 2px solid tomato to a div. Only the div gets a border; its paragraphs don't. border is not inherited, so the paragraphs use the initial value border-style: none.

03A declaration always beats inheritance

Inheritance is only used when the cascade found no declaration. Any matching rule, even the browser's default a { color: -webkit-link } or a weak * selector, wins over the inherited value. That's why links stay blue inside a red paragraph.

style.csswhole filecss
.warning { color: red; }
/* <p class="warning">Read <a href="#">this</a></p>
   the link stays blue: the browser's a { color } rule beats inheritance */
.warning a { color: inherit; }  /* now the link follows the paragraph */

04Use the four keywords

Each keyword answers a different question: inherit ("copy my parent"), initial ("use the spec's default"), unset ("act as if I wrote nothing"), revert ("go back to the browser's default").

keywords.csswhole filecss
a.plain   { color: inherit; }     /* parent's colour */
div.x     { display: initial; } /* inline! the spec default */
div.y     { display: unset; }   /* not inherited, so initial: inline */
div.z     { display: revert; }  /* browser default for div: block */
.card *   { all: unset; }       /* every property at once */

05Reset form controls

Write this once in your stylesheet so buttons and inputs match the page's text instead of the browser's control font.

style.csswhole filecss
button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

Try it yourself

  1. 1

    Inherit the border on purpose

    In the first example, predict what p { border: inherit; } does. Then add it. The paragraph now draws its own tomato border inside the box's border, and the console reports 3px.

  2. 2

    Fix the button

    In the first example, add button { font: inherit; color: inherit; }. Run it: the button now uses Georgia and navy, and both questions print true.

  3. 3

    Break the line-height

    In the third example, change .big to font-size: 48px. Predict the two line-heights before running (72px and still 24px).

Code & diagrams

What flows down and what doesn't New tab

Add `button { font: inherit; color: inherit; }` to the CSS and run again: the last two lines turn `true`.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Paragraph colour is navy? true
Paragraph font: Georgia, serif
Paragraph border width: 0px
Button uses the box font? false
Button colour is navy? false
inherit, initial, unset and revert New tab

`color` is inherited, so `unset` behaves like `inherit`. `display` is not inherited, so `unset` behaves like `initial`, which is `inline`. Only `revert` gives a div back its normal `block`.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

color: inherit -> seagreen
color: initial -> black
color: unset -> seagreen
color: revert -> seagreen
display: initial -> inline
display: unset -> inline
display: revert -> block
Why line-height should be a plain number New tab

With 150%, the parent turns it into 24px and the 32px child inherits 24px, so its lines overlap. With 1.5, the child inherits the ratio and gets 32 × 1.5 = 48px.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

line-height: 1.5 on the parent -> child line-height 48px
line-height: 150% on the parent -> child line-height 24px

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Use display: initial to "reset" a div

A rule set .panel { display: flex; } and you want one panel back to normal, so you write .panel.simple { display: initial; }.

terminal
$ the page shows
── what you'll see ──
The panel sits on the same line as the text around it and its width and height are ignored.

Break #2

A link that won't take the paragraph's colour

Write .alert { color: white; background: crimson; } on a paragraph that contains a link.

terminal
$ the page shows
── what you'll see ──
The paragraph text is white, but the link inside is dark blue on red and hard to read.

Myth vs fact

Myth

Every property is inherited.

Fact

Only some are, mostly text properties. Box and layout properties like margin, padding, border, background and width are not.

Myth

initial means the browser's default for that element.

Fact

initial is the specification's default for the property, the same for every element. The per-element browser default is what revert gives you.

Myth

Inheritance beats a weak selector like *.

Fact

Inheritance has no strength at all. It is only used when the cascade found no declaration. * { color: black } beats a colour inherited from body.

Myth

opacity and text-decoration are inherited because children change too.

Fact

Neither is inherited. With opacity, the parent and all its children are painted as one group and then faded. With text-decoration, the parent's underline is drawn across its children's text. Setting the property on a child can't undo either.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Inheritance passes the computed value through the element tree (the DOM, including Shadow DOM: a component's shadow content inherits from its host). That is why CSS custom properties, which are inherited, are the standard way to theme Web Components.

  • ▸

    visibility is inherited but can be overridden: a child with visibility: visible shows inside a visibility: hidden parent. display: none is not inherited, yet it removes the entire subtree, which no child can undo.

  • ▸

    all: unset resets every property except direction and unicode-bidi (and doesn't touch custom properties). all: revert is usually what people want for "undo the author styles on this widget", because unset also strips the browser's useful defaults, such as display: block and list bullets.

  • ▸

    Browsers optimise inheritance by sharing computed style objects between siblings with identical styles, so setting text styles high in the tree (on body or a component root) is cheap and keeps the style data small.

Remember this

  1. 1

    Elements are nested: a <p> inside a <div> is the div's child, and the div is its parent. Inheritance means: when the cascade finds no declaration for an inherited property on an element, the element takes the value its parent has. Set color: navy on body and every paragraph, list and heading inside turns navy, without one rule each.

  2. 2

    The specification marks every property as inherited or not inherited. Inherited ones are mostly about text: color, font-family, font-size, font-weight, font-style, line-height, letter-spacing, text-align, text-indent, text-transform, white-space, visibility, cursor, list-style, direction, border-collapse and all custom properties (--brand, Topic 3.6). Not inherited: box and layout properties such as margin, padding, border, background, width, height, display, position, overflow, opacity and transform. Imagine a border that was inherited: every child would draw its own border inside the parent's.

  3. 3

    A non-inherited property with no declaration gets its initial value, the default written in the specification for that property: border-style: none, background-color: transparent, display: inline, margin: 0. (Headings and paragraphs have margins only because the browser's default stylesheet gives them some.)

  4. 4

    Children inherit the parent's computed value, the value after relative units are worked out. If the parent has font-size: 2em and that computes to 32px, children inherit 32px, not "2em". This is also why line-height: 1.5 (a plain number) is better than line-height: 150%: the number is inherited as a ratio and recalculated for each child's font size, while the percentage is turned into a fixed length on the parent and inherited as that length.

  5. 5

    Four keywords work on every property and let you choose: inherit takes the parent's value, even for a non-inherited property (border: inherit). initial uses the specification's initial value (watch out: display: initial is inline, even on a div). unset acts like inherit for inherited properties and like initial for the rest, as if no rule had been written. revert rolls the property back to what the browser's default stylesheet would give it (display: revert on a div gives block). A fifth, revert-layer, rolls back to the previous cascade layer (Topic 2.5).

  6. 6

    Form controls (button, input, select, textarea) are the famous exception in practice. font is an inherited property, but the browser's default stylesheet sets a font on these elements, and any declaration beats inheritance. So buttons ignore your body font until you write button, input, select, textarea { font: inherit; }, a line found in almost every CSS reset.

Explain it without notes

01

What is inheritance in CSS, and when does it apply?

02

Give five inherited and five non-inherited properties, and explain why border is not inherited.

03

Explain the difference between inherit, initial, unset and revert using display on a div.

04

Why is line-height: 1.5 recommended over line-height: 150%?

Practice

01

Set the whole page's text to dark gray #333, the font to Georgia, serif and the line-height to 1.6 with a single rule, and make buttons use the same font and colour.

02

A navigation bar has a dark background and white text: .nav { background: #222; color: white; }. Its links are still blue. Fix it so the links are white, without writing white twice.

Trade-offs

  • ↔

    Setting text styles once on body and letting them inherit keeps CSS short, but makes a component's look depend on where it is placed; setting them on the component itself is more predictable but repeats values (custom properties, Topic 3.6, are the middle ground).

  • ↔

    all: unset gives a clean slate for a custom widget but strips accessibility-relevant defaults like focus outlines and display: block; all: revert keeps browser defaults but leaves more to override.

Done when you can

  • I can say whether a common property is inherited or not.

  • I know inheritance only applies when no declaration matched.

  • I can use inherit, initial, unset and revert correctly.

  • I know children inherit computed values, and why line-height should be a number.

  • I can make form controls use the page font.