Say you’re building a web page and want all your hyperlinks to be orange to stand out from the other text on the page. Also, for internal links, you not only want to change the font color — you also want to bold them for extra emphasis.
To do this, you add CSS selectors targeting all link elements and the link elements that contain your website name specifically (these are your internal links). But, when you preview the front end of your site, you don’t see the correct formatting for your internal links. What’s the deal?
You likely broke one of the CSS specificity rules and, as a result, will have to backtrack in your code to try to fix the mistake. It’s a pain, but very common. CSS specificity is one of the most difficult — but important — concepts to learn in CSS and frameworks like Bootstrap.
What is specificity in CSS?
In CSS, specificity is a measurement of relevance based on the type and order of CSS selectors in a document. In cases when an HTML element or a group of elements is targeted by multiple CSS selectors, the rules of CSS specificity tell the web browser which CSS declarations should be applied.
Before we look at the different rules of CSS specificity, let’s define the levels of specificity of each type of CSS selector. Below is the “specificity hierarchy,” which lists selector types from the highest specificity to the lowest specificity.
- ID selectors: ID selectors are the most specific kind of selector. They select an element based on its ID attribute (e.g., #my-id).
- Class selectors, attribute selectors, and pseudo-class selectors: These three selector types have equal specificity.
- Class selectors select all elements in a CSS class (e.g., .my-class).
- Attribute selectors select all elements with a given attribute (e.g., p[target]).
- Pseudo-class selectors select elements only when in a special state, like visited or hover (e.g., button:hover).
- Type selectors: These select all HTML elements that have a given node name and have the syntax element (e.g., div).
- Universal selector: The universal selector (*) has no effect on specificity.
CSS Specificity Rules
There are a few rules of CSS specificity you should know before you start writing your CSS.
Rule 1: The CSS selector with higher specificity applies.
If an HTML element is targeted by multiple selectors, then the browser will apply the CSS rule of the selector with the highest specificity.
For example, a paragraph element is targeted by both an ID selector and a class selector. Because the ID selector has higher specificity, the CSS style belonging to the ID selector is applied to the element over the class selector.
Let’s look at another example: Say you want all buttons to be blue across your website. You’d add a class selector to define all elements under the button class to have a blue background color.
But, if you want the subscribe button on your homepage to be an exception so that it’s more eye-catching, you can use an ID selector to define the one button with the ID “homepage” to have an orange background color. All buttons without the ID “homepage” will still follow the CSS rule of the class selector.
Rule 2: If CSS selectors have equal specificity, then the last rule in the document applies.
If multiple selectors are applied to the same HTML element and they have the same level of specificity (e.g., a class selector and an attribute selector), then the browser will apply the CSS rule of the selector that appears last in the stylesheet.
Taking from the example from above, say you have two declaration blocks for your buttons, and both use the button class. The second declaration block will apply, since it is the final one written in the document.
Rule 3: Inline CSS has the highest specificity.
CSS can be written in three ways: inline, inside a <style> tag in an HTML document, or in an external CSS stylesheet. Inline styling, otherwise known as the “embedded stylesheet,” has the highest specificity and automatically takes precedence.
This makes sense considering the previous rule that order matters. Inline CSS is the “closest” to the HTML element, so it is more specific and is therefore applied. Let’s look at an example demonstrating this rule below.
However, you should avoid internal CSS when possible, since it makes your code more difficult to maintain down the road.
How do you override specificity in CSS?
Although it might be tempting to take advantage of this property rather than following the other rules of specificity, we don’t recommend it. The !important property is considered a poor practice because it breaks the natural behavior of stylesheets, which makes maintaining and debugging your website much more difficult.
There are some use cases in which the !important property is okay to use, like when you’re defining utility classes, so we’ll briefly look at an example below.
Say you want any element targeted by the button class to look like the same button. Then you’d apply unique style properties with the .btn class selector. All good for now.
While building out your web page, you add a new section with the ID name “content” containing a link with the button class. You also add another rule to your CSS, defining all <a> elements with the ID name “content” to have a dotted blue border.
You now have two selectors targeting the same HTML element. And, as we know, because an ID selector has a higher specificity than a class selector, the CSS style of the ID selector takes precedence over the CSS style of the class selector. The second <a> element would therefore have a blue dotted border instead of a solid black one.
To avoid this and ensure that the style properties of the .btn class apply to all elements under that class name, regardless of the selector types or order, you can add the !important property.
Getting Specific with Your CSS
Understanding the rules of CSS specificity is important for having complete control over your HTML and CSS. With this knowledge, formatting will show up like you expect so you won’t have to go searching for a mistake in your code.
Editor's note: This post was originally published in July 2020 and has been updated for comprehensiveness.