Inheritance

The CSS Podcast - 005: Inheritance

Say you just wrote some CSS to make elements look like a button.

<a href="http://example.com" class="my-button">I am a button link</a>
.my-button {
  display: inline-block;
  padding: 1rem 2rem;
  text-decoration: none;
  background: pink;
  font: inherit;
  text-align: center;
}

You then add a link element to an article of content, with a class value of .my-button. However there's an issue, the text is not the color that you expected it to be. How did this happen?

Some CSS properties inherit if you don't specify a value for them. In the case of this button, it inherited the color from this CSS:

article a {
  color: maroon;
}

In this lesson you'll learn why that happens and how inheritance is a powerful feature to help you write less CSS.

Inheritance flow

Let's take a look at how inheritance works, using this snippet of HTML:

<html>
  <body>
    <article>
      <p>Lorem ipsum dolor sit amet.</p>
    </article>
  </body>
</html>

The root element (<html>) won't inherit anything because it is the first element in the document. Add some CSS on the HTML element, and it starts to cascade down the document.

html {
  color: lightslategray;
}

The color property is inherited by default by other elements. The html element has color: lightslategray, therefore all elements that can inherit color will now have a color of lightslategray.

body {
  font-size: 1.2em;
}
p {
  font-style: italic;
}

Only the <p> will have italic text because it's the deepest nested element. Inheritance only flows downwards, not back up to parent elements.

Which properties are inherited by default?

Not all CSS properties are inherited by default, but there are a lot that are. For reference, here is the entire list of properties that are inherited by default, taken from the W3 reference of all CSS properties:

How inheritance works

Every HTML element has every CSS property defined by default with an initial value. An initial value is a property that's not inherited and shows up as a default if the cascade fails to calculate a value for that element.

Properties that can be inherited cascade downwards, and child elements will get a computed value which represents its parent's value. This means that if a parent has font-weight set to bold all child elements will be bold, unless their font-weight is set to a different value, or the user agent stylesheet has a value for font-weight for that element.

How to explicitly inherit and control inheritance

Inheritance can affect elements in unexpected ways so CSS has tools to help with that.

The inherit keyword

You can make any property inherit its parent's computed value with the inherit keyword. A useful way to use this keyword is to create exceptions.

strong {
  font-weight: 900;
}

This CSS snippet sets all <strong> elements to have a font-weight of 900, instead of the default bold value, which would be the equivalent of font-weight: 700.

.my-component {
  font-weight: 500;
}

The .my-component class sets font-weight to 500 instead. To make the <strong> elements inside .my-component also font-weight: 500 add:

.my-component strong {
  font-weight: inherit;
}

Now, the <strong> elements inside .my-component will have a font-weight of 500.

You could explicitly set this value, but if you use inherit and the CSS of .my-component changes in the future, you can guarantee that your <strong> will automatically stay up to date with it.

The initial keyword

Inheritance can cause problems with your elements and initial provides you with a powerful reset option.

You learned earlier that every property has a default value in CSS. The initial keyword sets a property back to that initial, default value.

aside strong {
  font-weight: initial;
}

This snippet will remove the bold weight from all <strong> elements inside an <aside> element and instead, make them normal weight, which is the initial value.

The unset keyword

The unset property behaves differently if a property is inherited by default or not. If a property is inherited by default, the unset keyword will be the same as inherit. If the property is not inherited by default, the unset keyword is equal to initial.

Remembering which CSS properties are inherited by default can be hard, unset can be helpful in that context. For example, color is inherited by default, but margin isn't, so you can write this:

/* Global color styles for paragraph in authored CSS */
p {
  margin-top: 2em;
  color: goldenrod;
}

/* The p needs to be reset in asides, so you can use unset */
aside p {
  margin: unset;
  color: unset;
}

Now, the margin is removed and color reverts back to being the inherited computed value.

You can use the unset value with the all property, too. Going back to the above example, what happens if the global p styles get an additional few properties? Only the rule that was set for margin and color will apply.

/* Global color styles for paragraph in authored CSS */
p {
    margin-top: 2em;
    color: goldenrod;
    padding: 2em;
    border: 1px solid;
}

/* Not all properties are accounted for anymore */
aside p {
    margin: unset;
    color: unset;
}

If you change the aside p rule to all: unset instead, it doesn't matter what global styles are applied to p in the future, they will always be unset.

aside p {
    margin: unset;
    color: unset;
    all: unset;
}

Check your understanding

Test your knowledge of inheritance

Which of the following properties are inheritable?

animation
Animations don't pass down to children.
font-size
🎉
color
🎉
text-align
🎉
line-height
🎉

Which value behaves like inherit unless there is nothing to inherit and then behaves like initial?

reset
not a valid value, try again!
unset
🎉
superset
not a valid value, try again!

Resources