CSS: Cascade, Inheritance, and Specificity
How conflicts are resolved in CSS
I recently had a phone interview and was asked some questions that I could have answered better. The purpose of this series of blog posts is to help me remember these concepts, so next time I will have a better answer. If others find these posts useful, all the better.
To determine what styles will be applied to elements in a web page, it is necessary to understand the CSS Cascade, Inheritance, and Specificity. I will consider each of these concepts one at a time.
CSS Cascade
CSS styles are cascaded based on their source and their order.
Source
There are several sources that can provide styling for a web page. They are:
- User Agent Stylesheet: browsers have default style sheets that apply default styles to a web document.
- User Stylesheet: a user can define a stylesheet that will override the default stylesheet provided by the browser.
- Author Stylesheet: the author of a web page usually provides one or more stylesheets that will override user agent and user stylesheets.
There is actually more to this rule than I describe here, but this is what I think you will encounter most often. More information can be found here.
Order
Author stylesheets can be provided as a separate file, in the <style>
tag of an HTML file, or inline as an attribute of an HTML tag. Multiple .CSS files can be added via a <link>
tag in the head of a webpage, and .CSS files can even be linked to other .CSS files. If the same style property is set more than once in different places in the author stylesheets, the one that is encountered last by the browser is used.
The order in which the browser looks at stylesheets is determined by the order in which stylesheets are included in the HTML file. Stylesheets are added to a HTML file in the head section. The browser looks at these stylesheets in the order they are encountered in the file from top to bottom. If a stylesheet imports another stylesheet using an @import statement, then the imported stylesheet is placed at the beginning of the stylesheet that imports it.
It does not matter if the stylesheets are imported into an HTML file with a <link>
tag, or included within an HTML file within a pair of <style>
tags. The browser will look at whatever stylesheet it finds first, and styles that it encounters later will override styles it encountered earlier.
The last styles in the cascade order are the ones that are defined as a style attribute on an HTML tag. These will override stiles from external stylesheets and from a style tag in the head.
Inheritance
Styles applied to a parent element are inherited by a child element in an HTML file. For example, if there is a paragraph tag within a div tag, setting the color property of the div tag to red will cause the text within the paragraph tag to be red. If the color property of the paragraph tag is also set, it will override the color property inherited from the div tag.
Specificity
In CSS, selectors are used to define which elements in your HTML will use the styles you are defining. There are several types of CSS selectors, the most common being the HTML tag name, a class name, and an id. These can also be combined, For example div.red
will select any div
with a class of red. To calculate specificity, values are assigned to each selector type.
- Type selectors (HTML tag names such as
<div>
or<p>
): 1 - Class selectors(
class=”red”
): 10 - ID selectors (
id=”first”
): 100 - inline styles: 1000 (yes, I know this last one is not a selector)
The specificity of a CSS selector is calculated by adding these numbers. For example:
div.red
: this is a type selector (div
) worth 1 and a class selector (.red
) worth 10, for a total of 11.p#first
: this is a type selector (p
) worth 1 and a class selector (#first
) worth 100, for a total of 101.
CSS selectors with a higher specificity value override CSS selectors with a lower specificity value.
p.blue {
color: blue;
}
p {
color: red;
}
With the above CSS, a p
tag with a class of blue will have blue text, even though the other CSS rule appears later in the file.
Putting it all together
If an HTML element does not have a particular CSS property set, but its parent element does, then that property will be determined by inheritance. If that element does have the property set in CSS, then it will override the property from its parent. If that property is set again, later in the CSS cascade, it will override the property set earlier, unless the property set earlier had a higher specificity.
There is one more rule we have not discussed yet. If !important
is included as part of a CSS property like this:
p {
color: red !important;
}
It will override rules later in the cascade or with a higher specificity.
For larger projects, it can become difficult to trace from where an element is getting its style. Web browser developer tools can help some with this. Naming conventions, like BEM, have been developed to help manage CSS in big projects. There are also tools, like CSS Modules, that makes it so that all class names are scoped locally. Finally, there are CSS-in-JS libraries, like Emotion, that avoid the specificity issues with CSS.
Other Stories in this Series: