---
title: 'Inheritance and Default Values'
source: 'https://academia.sh/en/courses/css-fundamentals/inheritance-and-default-values'
course: 'Visual Presentation with CSS'
language: en
updated: '2026-08-17T18:09:17+00:00'
license: 'CC BY-SA 4.0'
---

# Inheritance and Default Values

How the value of a property no declaration reaches is determined; inherited and non-inherited properties, initial value, and the inherit, initial, unset, and revert keywords.

The cascade picks the winner among declarations that match an element. One problem
remains: what happens if no declaration matches at all? If no rule writes `color` to a
cell in the measurement table, what is that cell's text color?

The gap is filled by two separate mechanisms. Some properties **inherit** their value from
the parent element; the rest fall back to a defined **initial value**. This lesson
separates the two mechanisms, gives the reason behind which property is subject to which
one, and defines the keywords that call each of them explicitly.

## Inheritance Works Down the Tree

**Inheritance** is a property's value passing from parent element to child element down
the document tree. Not every property inherits; which property inherits is part of the
property's definition, and it is not arbitrary.

Roughly: properties that **determine the appearance of text** inherit — `color`,
`font-family`, `font-size`, `font-weight`, `line-height`, `text-align`,
`letter-spacing`, `visibility`. Properties that **determine the geometry of a box** do not
inherit — `margin`, `padding`, `border`, `width`, `height`, `background`, `display`,
`position`.

The reason for the distinction is usefulness. Setting a section's typeface once and
having all the text inside it take it on is an ordinary thing to want; giving a section a
border and wanting every paragraph inside it to also get a border is not. Inheritance is
open in decisions where repetition is ordinary.

The inherited value is the parent element's **computed** value, not the text written in
the source. If a parent element has `font-size: 150%` written on it, what passes to the
child is not the text `150%`, but that percentage's resolved result. This distinction is
handled with numbers in the units lesson.

## Initial Value Is Not the Browser Default

If no declaration reaches a non-inherited property, the **initial value** is used. This
value is written into the property's definition and is independent of implementation.

There is a distinction here that is commonly confused. A `div` element producing a block
box does not come from the `display` property's initial value — the `display` property's
initial value is `inline`. A `div` element being block is because the browser's own
default style file has `div { display: block }` written in it.

The distinction can be summarized as: **the initial value comes from the language's
definition, the browser default comes from a style file.** The first takes effect not when
no rule is written, but when no rule **wins**; the second is a declaration capable of
winning and, as the previous lesson showed, is the weakest source in the cascade.

## Running Value Resolution

The following program takes declarations that won the cascade as input and walks down the
tree, resolving each element's value for four properties. Each line ends with where the
value came **from**.

```js
// inheritance.mjs — runs value resolution down the tree
const INHERITED = new Set(["color", "font-family", "line-height", "text-align", "visibility"]);
const INITIAL = {
  "color": "canvastext", "font-family": "serif", "line-height": "normal",
  "text-align": "start", "visibility": "visible", "border-color": "currentcolor",
  "background-color": "transparent",
};

// winning declarations (cascade result) — node path -> {property: value}
const winners = {
  "body":                         { "color": "#1c2733", "font-family": "system-ui" },
  "body/main":                    {},
  "body/main/table":              { "text-align": "right", "border-color": "#d5dbe0" },
  "body/main/table/tr":           {},
  "body/main/table/tr/td.name":   { "text-align": "start" },
  "body/main/table/tr/td.missing":{ "color": "inherit", "text-align": "unset",
                                     "border-color": "unset", "font-family": "initial" },
};

const tree = { name: "body", children: [ { name: "main", children: [ { name: "table", children: [
  { name: "tr", children: [ { name: "td.name", children: [] }, { name: "td.missing", children: [] } ] },
] } ] } ] };

const PROPERTIES = ["color", "font-family", "text-align", "border-color"];

function resolve(node, path, parentValues) {
  const fullPath = path ? `${path}/${node.name}` : node.name;
  const written = winners[fullPath] ?? {};
  const values = {};
  for (const prop of PROPERTIES) {
    let v = written[prop];
    let source;
    if (v === undefined) {
      // no declaration: take from parent if inherited, else initial value
      if (INHERITED.has(prop) && parentValues) { v = parentValues[prop]; source = "inherited"; }
      else { v = INITIAL[prop]; source = "initial"; }
    } else if (v === "inherit") {
      v = parentValues ? parentValues[prop] : INITIAL[prop]; source = "inherit";
    } else if (v === "initial") {
      v = INITIAL[prop]; source = "initial-keyword";
    } else if (v === "unset") {
      if (INHERITED.has(prop) && parentValues) { v = parentValues[prop]; source = "unset->inherited"; }
      else { v = INITIAL[prop]; source = "unset->initial"; }
    } else {
      source = "declared";
    }
    values[prop] = v;
    console.log(`  ${prop.padEnd(12)} = ${String(v).padEnd(12)} (${source})`);
  }
  for (const c of node.children) {
    console.log(`${fullPath}/${c.name}`);
    resolve(c, fullPath, values);
  }
}

console.log("body");
resolve(tree, "", null);
```

```
body
  color        = #1c2733      (declared)
  font-family  = system-ui    (declared)
  text-align   = start        (initial)
  border-color = currentcolor (initial)
body/main
  color        = #1c2733      (inherited)
  font-family  = system-ui    (inherited)
  text-align   = start        (inherited)
  border-color = currentcolor (initial)
body/main/table
  color        = #1c2733      (inherited)
  font-family  = system-ui    (inherited)
  text-align   = right        (declared)
  border-color = #d5dbe0      (declared)
body/main/table/tr
  color        = #1c2733      (inherited)
  font-family  = system-ui    (inherited)
  text-align   = right        (inherited)
  border-color = currentcolor (initial)
body/main/table/tr/td.name
  color        = #1c2733      (inherited)
  font-family  = system-ui    (inherited)
  text-align   = start        (declared)
  border-color = currentcolor (initial)
body/main/table/tr/td.missing
  color        = #1c2733      (inherit)
  font-family  = serif        (initial-keyword)
  text-align   = right        (unset->inherited)
  border-color = currentcolor (unset->initial)
```

Three observations follow from the output.

`color` and `font-family` were only declared on the `body` element, and carried down five
generations to the cells. A declaration written at the root of the tree affects the entire
subtree.

`border-color` was `#d5dbe0` at the table but dropped back to `currentcolor` at the row.
Border color is not an inherited property; a border color given to the table does not
pass to the cells. This is why setting up a border on a table requires writing a rule to
the cells as well.

`text-align` became `right` at the table and inherited down to the row and cells; a
declaration on the `td.name` element overrode it to `start`. Inheritance does not hold
once there is a declaration on the child element — inheritance is the weakest source and
is always overridden by a declaration.

## Four Keywords

There are four keywords that can be written to any property's value. The output's last
block shows three of the four.

`inherit` — forces even a non-inherited property to be taken from the parent element.
`color: inherit` was written on `td.missing`, and the value came from above. This is
meaningful on a non-inherited property; writing `border-color: inherit` is a way to pull
the border color from above.

`initial` — returns to the property's initial value. In the output, the cell with
`font-family: initial` dropped to the value `serif`; the inheritance of `system-ui` from
above was cut. This result is often not the one desired: `initial` goes back to the
language's definition, not to the page's design.

`unset` — behaves conditionally: if the property is an inherited one, it acts like
`inherit`; if not, like `initial`. In the output, `text-align: unset` dropped to
inheritance, `border-color: unset` to the initial value. This is the answer to the
question "what would this be if this declaration had never been written at all."

`revert` — is the fourth, and answers a different question: it returns the value to what a
**weaker source** would have won. Writing `revert` in author style means going back, on
that property, to the browser default. The difference from `initial` shows up here: writing
`color: initial` on a link takes the color to the language's initial value, while
`color: revert` takes it to the color the browser has defined for links.

All four can be written to every property at once with the `all` shorthand. `all: revert`
isolates an element from author style; `all: unset` keeps inherited properties and resets
the rest.

## Value Stages

The term "computed value," which came up in this section, needs to be defined. A
declaration's value goes through several stages from what is written to what ends up on
screen:

| Stage | What happens |
|---|---|
| declared value | The text written in the source |
| cascaded value | The declaration that won the cascade |
| specified value | If there is no winner, filled in with inheritance or initial value |
| computed value | Relative units resolved, the form passed on by inheritance |
| used value | The final form once layout has been performed |

The stage carried by inheritance is the **computed** value. If a parent element has
`font-size: 1.5em` written on it, the child does not inherit the text `1.5em`, it inherits
that expression's resolved result — otherwise it would be multiplied again at every
generation, and the font size would grow exponentially.

The used-value stage, on the other hand, waits for layout. In the declaration
`width: 50%`, the computed value is still a percentage; the exact number only emerges once
the containing box's width is known. This stage will be covered in detail in the box model
topic.

## Using Inheritance in the Station Page

```css
/* station.css — step 7: using inheritance as a base */
body {
  color: #1c2733;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
}

/* form controls do not inherit typography by default */
input, select, textarea, button {
  font: inherit;
  color: inherit;
}

.measurement-table { border-collapse: collapse; }
.measurement-table th,
.measurement-table td { border-block-end: 1px solid #d5dbe0; }
```

The second rule closes an exception. Form controls do not take their typography from the
document; they carry their own default typefaces. Writing `font: inherit` removes this
exception and ties the controls to the document's typography.

The third group shows that, because border color is not inherited, the border has to be
written to the cells separately — the direct consequence of the behavior seen in the
output's fourth block.

## Summary

- A property either inherits or, if there is no declaration, falls back to its initial
  value; which applies is written in the property's definition, and text properties
  inherit while box-geometry properties do not.
- The initial value comes from the language's definition; the browser's default
  appearance comes from a style file and is the weakest source in the cascade.
  `display: block` is not an initial value, it is a declaration written in that file.
- Inheritance is the weakest source: if there is a declaration on the child element for
  that property, inheritance does not apply.
- `inherit` forces the value from above, `initial` returns to the language's initial
  value, `unset` picks between the two based on the property's kind, `revert` returns to
  the value of a weaker source.
- What inheritance carries is the computed value; relative units are resolved before
  being carried, otherwise they would be multiplied again at every generation.

## Next Step

Throughout this topic, which elements rules reach and which value wins have been
resolved. The value is settled, but what that value means has not been established yet.
Where on a cell does `padding: 8px` add eight pixels? What is the total width of a box
given a width? The next topic defines the model every element turns into a box, and works
through that box's sections with arithmetic.
