PLAINFINCH learn by building

Inheritance

You will be able to tell which styles pass from a parent element to its children and control that yourself.

What does inheritance mean in CSS?

When an element has no value of its own for a property, some properties take the value from the parent element. Set color on an <article> and every heading, paragraph and <strong> inside it turns the same colour without any extra rules. That is inheritance.

It only fills gaps. If any rule targets the child directly, even a low-specificity p selector, that value wins over anything inherited. Inherited values have no specificity at all, which surprises people who expect an id on the parent to beat a type selector on the child.

FigureAn inheritance tree: color and font set on body flow down to article, h2, p and strong, while the border on article does not pass to its children, and the button does not take the font by default.An inheritance tree: color and font set on body flow down to article, h2, p and strong, while the border on article does not pass to its children, and the button does not take the font by default.
Text properties set on body flow to every descendant. Box properties like border stay on the element that declared them, and form controls such as button skip the inherited font unless you opt in.

Which properties inherit and which don't?

The pattern is easy to remember: properties about text inherit, properties about the box don't. Text properties include color, font-family, font-size, font-weight, line-height, letter-spacing, text-align, visibility and cursor. Set them once high in the tree and they spread down.

Box properties include margin, padding, border, background, width, height, display and position. Imagine if border inherited: a border on an article would draw another border around every paragraph and every word in bold inside it. Keeping those properties local is what you want almost every time.

When you are unsure, check the property's reference page, which states "Inherited: yes" or "no". In DevTools, the Styles panel shows inherited rules under headings like "Inherited from article.recipe", and greys out the declarations from those rules that don't inherit.

  • Inherit: color, font-*, line-height, letter-spacing, text-align, list-style, visibility, cursor.
  • Don't inherit: margin, padding, border, background, width, height, display, position, overflow.

Why set font and colour on body?

Because inheritance does the rest. A few declarations on body give every element on the page a consistent typeface, size, line height and text colour. Components then only change what is different, such as a heading font or a muted caption colour.

Use body rather than * for this. The universal selector targets every element directly, which beats inheritance everywhere and stops a .card from passing its own colour down to its children. Values set on body stay as defaults that any ancestor can change for its own subtree.

Setting the font size on html instead works as well, and it is where rem units take their reference size from. Many sites leave the root size alone so a reader's browser setting is respected, and set the font family and colour on body.

body {
  font-family: Georgia, serif;
  line-height: 1.5;
  color: #3b2f2a;
  background: #fbf8f2;
}

Why don't buttons and inputs use the page font?

Browsers style form controls to look like the operating system's controls, and their user agent stylesheet sets an explicit font on button, input, select and textarea, typically a system font at about 13.33px. An explicit value beats inheritance, so your body font never reaches them.

The fix is one rule near the top of your stylesheet. font: inherit resets family, size, weight, style and line-height in one go. Many resets also add color: inherit and letter-spacing: inherit for the same reason.

AI-generated CSS often styles buttons with a separate font-family copy of the body font. That works until the body font changes. Inheriting keeps a single source of truth.

button,
input,
select,
textarea {
  font: inherit;
}

What do inherit, initial, unset and revert do?

These keywords work on every property. inherit takes the parent's computed value, even for a property that wouldn't normally inherit. border-color: inherit on a child copies the parent's border colour, for instance.

initial sets the property to its starting value from the specification, which is often not what you expect. The initial value of display is inline, even for a <div>, because the block display of a div comes from the browser stylesheet. Writing display: initial on a div makes it inline.

unset acts like inherit for inherited properties and like initial for the rest. revert rolls the property back to what the browser's stylesheet would give it, so display: revert on a div gives block again. All four are supported in all current browsers.

The shorthand all applies a keyword to every property at once. all: revert on a component removes your site styles from it and returns to browser defaults, which is handy for embedded content you want to start fresh.

.recipe a {
  color: inherit; /* links match the text */
}

.plain-list {
  list-style: revert; /* bring back bullets */
}

How do links fit into inheritance?

Links don't inherit text colour by default because the browser stylesheet gives a an explicit blue. That is why a dark card with light text can still show bright blue links. Writing color: inherit on links inside a component makes them match the surrounding text, and you can then mark them with an underline or weight instead.

Keep links distinguishable from surrounding text by more than colour alone. An underline is the clearest signal, and readers with colour vision deficiencies rely on it.

.card a {
  color: inherit;
  text-decoration-thickness: 2px;
}

How do you trace where an inherited value came from?

Select the element in DevTools and open the Computed tab. Find the property and expand it. You will see the chain of rules that offered a value, with the inherited one labelled by the ancestor it came from. Clicking it jumps to the rule in the Styles panel.

When a colour or font looks wrong deep in the page, this is usually faster than reading the stylesheet. A common finding is a forgotten color on a wrapper several levels up that every child inherits without anyone noticing.

Which inheritance surprises catch people out?

Percent and em values inherit as computed lengths. If a parent has font-size: 1.25em and the child inherits it, the child gets the parent's final pixel size, while a child that sets its own 1.25em grows again. The units lesson covers this compounding.

A unitless line-height such as 1.5 inherits as the number, so each child multiplies its own font size. A line-height in pixels or em inherits as a fixed length, so a large heading inside it can end up with overlapping lines.

Hiding with visibility: hidden inherits, so a child can opt back in with visibility: visible. display: none does not inherit and cannot be undone by a child, because the whole subtree is removed from layout.

Field notes

  • Some properties copy their value from the parent when the child sets none.
  • Text properties such as colour and font inherit, and box properties do not.
  • Setting font and colour on body gives the whole page a consistent look.
  • Buttons and inputs get their own font from the browser unless you tell them to inherit.

Easy to get wrong

The universal selector sets the colour on every element directly, so a parent like .card can no longer pass its own colour to its children.

Copying the font name means two places to update. Inheriting follows whatever the page uses.

The initial value of display is inline. revert returns to the browser's block.

Questions people ask

Does background inherit?

No. A child's background is transparent by default, so the parent's background shows through it. That looks like inheritance but the child's own value is still transparent.

Can I make a non-inherited property inherit?

Yes. Write inherit as its value on the child, such as border-color: inherit.

Do custom properties inherit?

Yes. A --brand variable set on body is available to every descendant, which is why design tokens are usually declared on :root.

What is the difference between unset and revert?

unset goes to the inherited or specification initial value. revert goes back to the browser's default for that element, which is usually what you actually want.

Keep going