Priority rules in CSS (specificity)

Complex style sheets often reveal contradictions between different rules. This happens when a property is given different values, with different selectors but targeting one or more identical elements.

This page describes the standard CSS mechanism for resolving these conflicts. You can also refer to the page on the @layer directive which allows you to implement another priority management: cascading layers.

The contradictory rules.

It is common for multiple CSS rules to be contradictory. This happens whenever you try to assign different values to the same property.

For example, the following two CSS rules contradict each other on one of the paragraphs. Indeed, the first rule requires that the element with the ID parag1 be red, while the second rule requires that paragraphs be blue. If the element parag1 is itself a paragraph, there is a contradiction.

#parag1a {color:red;} p {color:blue;}

Here is a more complete example that shows that it is not necessarily the last rule encountered that takes precedence over the previous ones. In this example, we see that the rule with an ID selector ( # ) takes precedence over the one defined on the class. As a result, the style applied to the ID (red color) takes precedence over the one applied to the class (blue color), even though the latter is stated afterwards.

p id="parag1a" class="exemple1a"
The first paragraph.
/p

p id="parag1b" class="exemple1"
The second paragraph.
/p

The specificity of selectors.

Reminder: the selector is what determines which element(s) a CSS rule applies to. In the example below, the selector is .inset. It designates all elements with the class="insert" attribute.

.inset {border:solid 1px silver;}

Not all selectors have the same specificity (priority). In the event of a contradiction between two rules, the one that applies is the one with the highest specificity. In general, selectors have a higher specificity the more precise they are. The very general selector * has a specificity of 0. Conversely, a selector on an identifier, which in principle concerns only one element of the page, has a specificity of 100.

To determine the specificity of a selector, consider the following logic:

  1. A rule marked with !important has a specificity of 10000.
  2. A rule written in the style attribute of an HTML tag has a specificity of 1000.
  3. A rule with a selector on an identifier ( # ) has a specificity of 100.
  4. A rule with a selector on a class ( . ) or a pseudo-class ( : ) has a specificity of 10.
  5. A rule with a selector on an element type ( p ) or pseudo-element ( :: ) has a specificity of 1.
  6. The star selector ( * ) has a specificity of 0.

Animations take precedence over all other declarations, except those that are noted!important. Which makes sense, otherwise the animations could never run. See the tutorial at animations in CSS. Transitions take precedence over all other rules, including those marked !important. See the transition property.

When a selector has multiple parts combined, the specificity of each part add up to give the overall specificity of the selector. One exception, however, is that when the selector is composed of several parts separated by commas, each part is considered a selector in its own right. Each of the parties may be given a different specificity.

Finally, when two conflicting rules have a selector of the same specificity, the last rule encountered overrides the values set by the previous rules.

Exemples :

/* Selector targeting an identifier -> specificity = 100 */ #edito {color:blue;} /* Selector targeting a pseudo-classe -> specificity = 10 */ :link {color:inherit;} /* Selector targeting an element type -> specificity = 1. */ p {font-size:1.1em;} /* Rule marked !important -> specificity = 10000 */ p {color:silver!important} /* A selector that target child images of the #edit element -> specificity = 101 */ #edit img {width:25%;} /* Selector for direct child of a cell -> specificity = 2 */ td > img {width:100%;} /* Selector targeting h1 or h2 titles -> specificity = 1 /* h1, h2 { ... }

Some particular selectors.

The :is() and :has() selectors get priority of the most selective selector among those passed as arguments.

:is(#edito, .introduction) /* Priority = 100 (that of #edito) */ :has(img) /* Priority = 1 (that of a selector per tag) */

The :not() selector takes precedence over the selector passed as an argument.

:not(:first-line) /* Priority = 10 (that of a pseudo-class) */

The :where() selector has a specificity of 0, although it is a pseudo-class.

The value !important.

The !important word can be added to any value in a CSS rule. He makes the rule a priority. In the example below, both paragraphs are turned red by their IDs. However, there is a rule based on the class that tries to turn them blue. But this rule is ineffective because the ID selector has higher priority. The last rule uses the !important value, and we can see on the second paragraph that it takes precedence over the ID.

The first paragraph.

The second paragraph.

Note: the !important declaration should be used as little as possible because it breaks the inheritance mechanism.

The placement of styles.

Things get more complicated if we consider that:

  • Multiple style sheets can be associated with the same page.
  • Styles can be written in the page itself (in the head section) or in the style attribute of HTML tags.
  • The browser has its own style sheet, which is applied to all the pages it displays.
  • The user (the reader or the Internet user) can define his own styles.
    For this reason we will have to distinguish between the styles of the user (the Internet user) and the styles of the author (the one who creates the pages).
    Reader styles are little used and tend to disappear completely. See the paragraph on user style sheets further down this page.

This brings up three kinds of styles: browser styles, those of the author (the web designer who worked on the site) and those of the user (the Internet user).

The processing of all these style sheets is done in the following order:

  • The browser performs an initial conflict resolution on its own style sheet. The values obtained will be used if no other style modifies them.
  • Secondly, it resolves any conflicts between the selectors of the user's style sheet. The resulting values override those in the browser style sheet.
  • Finally, the browser resolves conflicts of selectors on the author's style sheet or style sheets. These are attached to the page (using the link tag) and on the styles described within the page itself between the style and /style tags. The values obtained will be the ones that are ultimately used.

However, as the possibility for the user to define his own styles is in the process of disappearance, we can simplify all this and consider that:

  • The browser assigns the values defined in its own style sheet after resolving any conflicts.
  • The browser resolves selector conflicts on the author's styles and applies the resulting values instead of those in its own style sheet.

It is important to note something that is often misunderstood: styles written in the page itself, between style and /style tags. in the head section, are considered with the same priorities that the Author Styles from an external style sheet. Only the specificity of the selectors is taken into account.
Firefox seems to give them a small advantage by crawling them after the styles on the outer sheet, though, so they may be given a slight priority whether all other priority rules are neutral.

In summary, here's how priorities between different style sheets are managed, also considering the !important value. The list below is sorted from highest priority to lowest priority.

  1. Transition effects.
  2. The rules noted !important from the browser's style sheet.
  3. The rules noted !important from the user's style sheet.
  4. The rules noted !important from the author's style sheet.
  5. The animations.
  6. The rules of the author's style sheet.
  7. The rules of the user's style sheet.
  8. The rules of the browser style sheet.

The inspector

There is a particularly handy tool, provided by most browsers and often referred to as the "inspector". It is activated by right-clicking on one of the elements of the displayed web page:
right-click -> inspect

The inspector presents a lot of information, both about the HTML code and the CSS rules applied to the element that was clicked. It shows very well in particular the rule that is active and those that have been overridden by another rule of higher priority: the overloaded rules are scratched.

The inspector, in Chrome
Styles defined by the style attribute of HTML.
Styles defined between the style... /style tags, in the head section of the page.
Styles defined in the external style sheet.
Styles defined in the browser style sheet.

The user style sheet.

The user style sheet allows the user, i.e. the reader, to define his or her own styles, which will be applied to all the pages displayed.

This possibility is not used much and is not very useful because the user-defined styles are applied to all pages, without it being possible to make a difference from one page to another.

Chrome has disabled this possibility. Firefox no longer enables it by default. However, it is possible to activate it on Firefox with the flag toolkit.legacyUserProfileCustomizations.stylesheets (access flags on Firefox). You may need to restart Firefox.

User styles must be written to a file named userContent.css and saved in the profile folder. To create or edit this file, proceed as follows, for Firefox  :

  • Type about:support in the address bar.
  • Look for Profile folder and click on the Open folder button. The profile folder opens in Windows Explorer.
  • If necessary, create a sub folder named chrome in lowercase (yes the folder is named "Chrome").
  • Create or edit userContent.css file: write user styles to this file.
  • Restart Firefox.

What about HTML attributes?

In the past, it was common to define formatting directly by HTML attributes.

divfont color="blue"
Text in blue.
/font/div

CSS styles are ALWAYS prioritized over HTML attributes other than style. Attributes such as color, size, etc. should no longer be used since they are no longer standardized from HTML5.

divfont style="color:red" color="blue"
This text is indeed in red, despite the color attribute.
/font/div