Inheritance in CSS
Learn which CSS properties inherit by default, how to force inheritance with inherit, block it with initial, and use the all shorthand to write cleaner and more maintainable CSS.
When I first started writing CSS, I made a mistake I see beginners repeat all the time.
I’d set font-family: 'Inter', sans-serif on my <body> tag, then immediately start doubting myself. “Does my <h1> actually pick that up? What about the <p> tags? What if I have a <span> nested three levels deep?” So I’d just set the font-family on every single element. Just to be safe.
I was writing 20 lines of CSS where 2 would do the exact same job.
That’s what CSS inheritance is about: certain properties automatically flow from a parent element down to its children, grandchildren, and beyond. Set it once at the top, and everything inside picks it up, with no extra code needed.
In our previous article on the CSS Cascade, we talked about how CSS decides which style wins when multiple rules conflict. Inheritance is a different layer of that same system. It answers a slightly different question: where does a value come from when no rule explicitly sets it?
By the end of this article, you’ll know:
- Which CSS properties inherit by default, and which ones don’t
- How to force any property to inherit using the
inheritkeyword - How to block inheritance with
initial - What
unsetdoes and when it’s the smarter choice - How the
allshorthand lets you reset everything at once - How to put all of this together to write noticeably less CSS
Let’s go.
01What CSS Inheritance Actually Is
Every HTML page is a tree. <html> sits at the root, <body> lives inside it, and then all your headings, paragraphs, divs, and spans branch out from there, each one nested inside another.
Inheritance means: when certain CSS properties are set on a parent element, those properties automatically apply to every descendant, children, grandchildren, great-grandchildren, all the way down.
Think of it like family traits. You didn’t choose your eye color, it passed down from your parents. CSS works the same way for specific properties. You set color on <body>, and every text element inside inherits that color automatically.
Here’s the simplest example:
body {
color: #94a3b8;
font-family: 'Inter', sans-serif;
font-size: 16px;
line-height: 1.6;
}
Every <h1>, <h2>, <p>, <li>, <span> on your page will automatically use this color and font. You didn’t write a single rule targeting them. They inherited it.
The one important thing to get straight early: not every CSS property inherits. The CSS spec made a deliberate decision about which ones should pass down. Once you understand the logic behind that decision, the whole system clicks into place.
02The Inheritance Tree: Seeing It Flow in Real Code
Take this HTML structure:
<body>
<main>
<h2>CSS Inheritance</h2>
<p>Set it once. <span>It flows everywhere.</span></p>
</main>
</body>
Add this CSS:
body {
color: #94a3b8;
font-family: 'Inter', sans-serif;
font-size: 16px;
}
Here’s exactly what happens in the inheritance tree:
font-family: ‘Inter’
font-size: 16px
✓ inherits font-family
✓ inherits font-size
✓ inherits font-family
⚠ browser overrides font-size (2em)
✓ inherits font-family
✓ inherits font-size
Notice the amber warning on <h2>. The font-size property does inherit, but the browser’s built-in stylesheet has a specific rule that makes headings larger. That browser rule beats the inherited value because it’s more specific in the cascade. This is exactly what we covered in our CSS Cascade article. Inheritance only kicks in when nothing else, including browser defaults, has set a value for that element.
03Which CSS Properties Inherit by Default
The spec divides every CSS property into two categories: inherited and non-inherited. This isn’t a browser decision, it’s part of the CSS standard itself.
Text and Typography: The Natural Inheritors
The large majority of CSS properties that inherit by default are about text. Color, font, spacing, alignment. This makes complete sense: you want consistent typography across a section without setting it on every single child element.
✓ Inherits by Default
- color
- font-family
- font-size
- font-weight
- font-style
- font-variant
- line-height
- letter-spacing
- word-spacing
- text-align
- text-indent
- text-transform
- text-shadow
- list-style
- visibility
- cursor
- word-break
- white-space
- direction
✗ Does NOT Inherit
- margin
- padding
- border
- border-radius
- background
- background-color
- width / height
- display
- position
- top / right / bottom / left
- overflow
- box-shadow
- opacity
- transform
- flex / grid properties
- z-index
- outline
- animation
- float
The pattern is clear. Text-related properties inherit, layout and box-model properties don’t.
Why Layout Properties Refusing to Inherit is the Right Call
Imagine for a second that margin inherited. You’d set margin: 30px on a <section>, and every single paragraph, heading, and span inside it would also get 30px of margin on all sides. The page would look like it exploded.
Or if background-color inherited: you’d set a dark background on <body> and every nested div, every card, every button would also have that same dark background layered on top. You couldn’t give any element its own distinct background.
The spec made the right call. Text properties flow down because consistent typography is something you actually want. Layout properties stay put because layout needs precision and control at each individual level.
opacity: It’s not technically an inherited property, but it visually affects all children anyway. When you set opacity: 0.5 on a parent, the children appear semi-transparent too, because they’re rendered inside the parent’s compositing layer. The value isn’t inherited, but the visual effect bleeds through. If you only want to fade a background without affecting the text inside, use background: rgba() instead.
04Forcing Inheritance with the inherit Keyword
Here’s where it gets genuinely useful. Even if a property doesn’t inherit by default, you can force it to. The inherit keyword tells an element: “take whatever value your parent has for this property.”
.child {
border: inherit; /* border doesn't inherit by default, but now it will */
background: inherit; /* same here */
}
The inherit keyword works on absolutely any CSS property. Inherited or not. It always means the same thing: look at the parent and use its value.
The Most Common Real-World Use: Links Inside Colored Containers
You’ll hit this scenario constantly. A container has a custom text color, and you want the links inside to match. But the browser’s default stylesheet sets a specific color: blue (or similar) on anchor tags, and that browser default beats the inherited color from the parent.
<div class="notice">
<p>Read our <a href="#">complete guide</a> for full details.</p>
</div>
.notice {
color: #f59e0b; /* amber */
background: rgba(245, 158, 11, 0.1);
padding: 1rem 1.25rem;
border-radius: 10px;
}
/* The <p> inside will be amber, it inherits from .notice */
/* But the <a> stays blue, the browser overrides it */
/* Fix: force the link to inherit the amber */
.notice a {
color: inherit;
}
Here’s exactly what that looks like:
/* .notice a — no color rule */
/* .notice a { color: inherit; } */
One line. The link now matches the container’s amber color. This is probably the most practical use of the inherit keyword in everyday CSS.
05Stopping Inheritance with the initial Keyword
initial goes in the opposite direction. Instead of reaching up to grab the parent’s value, it resets the property to the CSS specification’s original default value, completely ignoring both the parent and the browser.
body {
color: #6366f1; /* indigo */
}
.hero-label {
color: inherit; /* explicitly gets indigo from body */
}
.footnote {
color: initial; /* ignores body's indigo, goes back to spec's initial value */
}
.hero-label will be indigo. .footnote will use the spec’s initial value for color, which in most environments resolves to the browser’s default text color (black or a system default, depending on OS).
initial does NOT mean “the browser’s default.” It means the CSS spec’s initial value. For most properties those happen to be the same, but not always. For example: the spec’s initial value for display is inline. But browsers render <div> as block by default. Writing display: initial on a div gives you display: inline, not display: block. Keep that in mind.
You’d use initial when you want to fully detach an element from whatever its ancestors are passing down, and you don’t want to hard-code a specific value. Instead of writing color: black, you write color: initial and let the spec decide.
06The unset Keyword: A Smarter Middle Ground
unset is a hybrid of the two. The rule is simple:
- If the property naturally inherits by default:
unsetacts exactly likeinherit - If the property doesn’t naturally inherit:
unsetacts exactly likeinitial
.element {
color: unset; /* color inherits by default → same as color: inherit */
font-size: unset; /* font-size inherits by default → same as font-size: inherit */
border: unset; /* border doesn't inherit → same as border: initial */
margin: unset; /* margin doesn't inherit → same as margin: initial */
}
On its own, unset can feel like a verbose way to write something you could just express directly. But it becomes genuinely powerful when paired with the all shorthand, which we’re about to get to.
Here’s a side-by-side visual of all three keywords in action:
Live Comparison: inherit vs initial vs unset on color
.parent
color: #ec4899 — this parent is styled pink
.child-one
color: inherit
I’m pink, too.
Grabs parent’s value directly.
.child-two
color: initial
I’m default grey.
Ignores parent. Goes to spec default.
.child-three
color: unset
I’m pink, too.
color inherits by default, so unset = inherit here.
07The all Shorthand: A Complete Property Reset in One Line
This one genuinely surprised me the first time I saw it in use.
The all property applies a single value to every CSS property on an element at once. Background, color, font, border, margin, padding, display, position: every single property, all in one go.
.clean-component {
all: unset;
}
One line. Every property is now reset. This is most useful when you’re building custom buttons, form inputs, or any component where browser defaults get in the way:
.custom-btn {
all: unset; /* wipe the browser's button styles completely */
/* Now build your own from a clean foundation */
display: inline-flex;
align-items: center;
padding: 0.6rem 1.25rem;
background: #6366f1;
color: #ffffff;
font-size: 0.9rem;
font-weight: 600;
border-radius: 8px;
cursor: pointer;
letter-spacing: 0.01em;
}
No wrestling with outline, appearance, font, or any of the browser’s default button quirks. You start fresh and build exactly what you want.
all: unset vs all: initial vs all: revert
Here’s how the three most common all values differ:
The all shorthand: three different reset levels on a button
/* No all property — fully styled */
/* all: unset — no styles remain */
/* all: revert — browser defaults restored */
/* Resets every property to the CSS spec's initial value.
Nothing inherits, nothing uses browser defaults. */
.hard-reset {
all: initial;
}
/* Smarter reset: non-inherited properties go to initial,
inherited properties still inherit from the parent. */
.smart-reset {
all: unset;
}
/* Rolls back everything to what the browser's built-in
stylesheet would set. Undoes your custom rules only. */
.browser-reset {
all: revert;
}
all: unset is usually what you want. It gives you a clean canvas while still respecting inherited text properties from the parent. Use all: revert when you’ve over-specified a component and want to undo just your own rules without rebuilding from absolute zero.
08Writing Far Less CSS by Leaning on Inheritance
This is the part that actually changes how you work. Let me show you a real contrast.
The “Set It Once” Approach: Stop Repeating Typography Rules
Here’s what a lot of beginners write when they want consistent fonts and colors across a page:
font-family: ‘Inter’, sans-serif;
color: #e2e8f0;
}
h2 {
font-family: ‘Inter’, sans-serif;
color: #e2e8f0;
}
p {
font-family: ‘Inter’, sans-serif;
color: #e2e8f0;
}
li {
font-family: ‘Inter’, sans-serif;
color: #e2e8f0;
}
span {
font-family: ‘Inter’, sans-serif;
color: #e2e8f0;
}
font-family: ‘Inter’, sans-serif;
color: #e2e8f0;
}
/* That’s it. Every element
inside body inherits both.
Update once, it changes
everywhere. */
These two code blocks produce identical results. The inheritance version is five times shorter, and if the brand font changes, you update it in exactly one spot.
A Real Card Component: Inheritance Doing the Heavy Lifting
Let’s look at something more realistic. A card component where inheritance handles the shared styles, and you only override what actually needs to differ:
<div class="card">
<h3 class="card-title">CSS Inheritance</h3>
<p class="card-body">Set styles once. Let them flow down naturally.</p>
<a class="card-link" href="#">Read more →</a>
</div>
/* Set shared defaults at the component root */
.card {
background: #1e293b;
padding: 1.5rem;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.05);
/* All text inside will inherit these */
color: #f8fafc;
font-family: 'Inter', sans-serif;
line-height: 1.6;
}
/* Only specify what actually needs to be different */
.card-title {
font-size: 1.2rem;
font-weight: 700;
margin: 0 0 0.5rem 0;
/* color and font-family: inherited from .card */
}
.card-body {
font-size: 0.92rem;
color: #94a3b8; /* slightly softer, so we override */
margin: 0 0 1rem 0;
/* font-family: inherited from .card */
}
.card-link {
font-size: 0.88rem;
font-weight: 600;
color: inherit; /* force link to use .card's white, not browser's blue */
text-decoration: underline;
}
The key line is color: inherit on .card-link. Without it, the browser’s default blue link color would override the white we set on .card. With it, the link uses the card’s color. Clean, intentional, and takes exactly one line.
This is the real-world pattern: set defaults at the component level, let children inherit the shared styles, and only override what genuinely needs to be different.
09CSS Inheritance Keywords: Quick Reference
| Keyword | What It Does | Best Used When |
|---|---|---|
| inherit | Takes the exact computed value from the parent element | A property doesn’t inherit by default but you want it to (links in colored containers, borders, etc.) |
| initial | Resets to the CSS specification’s original initial value | You want to fully detach from the parent without writing a specific value |
| unset | Acts as inherit if the property naturally inherits; acts as initial if it doesn’t |
Combined with all, or when you’re unsure which type of reset you need |
| revert | Rolls back to the browser’s built-in user-agent stylesheet value | You’ve over-specified something and want browser defaults back without rebuilding from zero |
| all | Applies one of the above values to every CSS property on the element simultaneously | Custom buttons, form inputs, or any component where browser defaults need a full wipe |
If you want to look up whether any specific property inherits, MDN’s CSS Inheritance reference is the definitive source. Every property page on MDN lists whether it’s inherited right in the definition block.
10Three Habits to Start Using Today
Here are three concrete things you can apply immediately:
1. Set typographic defaults on body, not everywhere. Put font-family, color, font-size, and line-height on body first. From there, only override what specific sections or components need to differ.
2. When a link looks wrong inside a colored section, reach for color: inherit first. It’s almost always the right solution, and it’s one line. This is the most commonly needed use of inherit in everyday CSS work.
3. When building custom buttons or inputs, start with all: unset. Browser styles on interactive elements are notoriously inconsistent across operating systems. A clean slate is much easier to work with than trying to undo a dozen defaults one by one.
11Up Next: Selectors, the Building Blocks of Every CSS Rule
We just wrapped up Batch 1 of this CSS series. From the introduction to CSS, through how the browser renders styles, through the cascade, and now inheritance: you now have a solid mental model of how CSS actually works at its core.
In Batch 2, we move into Selectors. The first article covers Universal, Type, Class, and ID Selectors: the four fundamental selector types, when each one is the right tool, and why over-relying on IDs will create headaches later. It’s a short but important topic that all the more advanced selector work builds on.
If you’ve been reading these articles in order, you’re in a genuinely good position. You understand the cascade, you understand inheritance, you know how to control the flow of styles. Most beginners skip these foundational concepts entirely and spend months confused about why their CSS “isn’t working.” You won’t have that problem.
Keep going. It gets more interesting from here.
Inheritance in CSS
Loading challenge…
Ready to Practice?
Select a difficulty level above to load your challenge.