CSS - Specificity

-

Specificity Hierarchy

In CSS, selectors have different levels of specificity, which determine which styles are applied to an element when there are conflicting rules. Understanding the specificity hierarchy is key to writing effective and maintainable CSS code. Here's a breakdown of the specificity hierarchy, from highest to lowest:

Inline styles

Inline styles, which are applied directly to an element using the style attribute, have the highest specificity. They take precedence over any other styles defined in external stylesheets or <style> tags.

Inline styles example

<p style="color: red;">This text will be red.</p>

IDs

ID selectors, which target a specific element with a unique ID, have the second-highest specificity. An ID selector is defined using the # symbol followed by the ID name.

ID selector example

#unique-element {
  background-color: yellow;
}

Classes, attributes, and pseudo-classes

Class selectors, attribute selectors, and pseudo-classes have the third-highest specificity. They are more specific than element selectors but less specific than IDs.

Classes, attributes, and pseudo-classes example

.class-name {
  font-weight: bold;
}

[type="text"] {
  border: 1px solid black;
}

a:hover {
  text-decoration: underline;
}

Elements and pseudo-elements

Element selectors and pseudo-elements have the lowest specificity. They target elements based on their tag name or a pseudo-element.

Elements and pseudo-elements example

p {
  font-size: 16px;
}

h1::before {
  content: "* ";
}

When multiple selectors target the same element, the browser applies the styles according to the specificity hierarchy. Inline styles take precedence over IDs, which take precedence over classes, attributes, and pseudo-classes, which in turn take precedence over elements and pseudo-elements.

Calculating Specificity

To find which styles apply to an element when there are conflicting rules, browsers calculate the specificity of each selector. Specificity is calculated based on a set of weight values assigned to different types of selectors.

Specificity weight values

The specificity of a selector is calculated using four components, each with a different weight value:

Component Weight Value
Inline styles (1, 0, 0, 0)
IDs (0, 1, 0, 0)
Classes, attributes, and pseudo-classes (0, 0, 1, 0)
Elements and pseudo-elements (0, 0, 0, 1)

The specificity value of a selector is the sum of its weight values for each component.

How to calculate the specificity of a selector

To calculate the specificity of a selector, follow these steps:

  1. Count the number of inline styles, IDs, classes/attributes/pseudo-classes, and elements/pseudo-elements in the selector.
  2. Multiply each count by its corresponding weight value.
  3. Sum up the weighted counts to get the final specificity value.

The selector with the highest specificity value takes precedence over others.

Examples of specificity calculations

Example 1

p {
  color: black;
}

.text {
  color: blue;
}
  • p: (0, 0, 0, 1) = 1
  • .text: (0, 0, 1, 0) = 10

The .text selector has a higher specificity, so the text will be blue.

Example 2

#unique-id {
  color: green;
}

p.text {
  color: red;
}
  • #unique-id: (0, 1, 0, 0) = 100
  • p.text: (0, 0, 1, 1) = 11

The #unique-id selector has a higher specificity, so the text will be green.

Example 3

<p class="text" style="color: orange;">Hello, world!</p>
#unique-id {
  color: green;
}

p.text {
  color: red;
}
  • Inline style: (1, 0, 0, 0) = 1000
  • #unique-id: (0, 1, 0, 0) = 100
  • p.text: (0, 0, 1, 1) = 11

The inline style has the highest specificity, so the text will be orange.

Specificity Rules

When working with CSS, you need to understand the rules that govern specificity. These rules help determine which styles are applied when there are conflicting selectors targeting the same element. Let's look at some key specificity rules:

Equal specificity: the latest rule counts

When two selectors have the same specificity, the one that appears later in the stylesheet takes precedence. This is because CSS cascades from top to bottom, and the last rule encountered overrides previous ones with equal specificity.

Equal specificity example

p {
  color: black;
}

/* This rule will override the previous one */
p {
  color: blue;
}

ID selectors have a higher specificity than attribute selectors

ID selectors are more specific than attribute selectors. This means that if an element is targeted by both an ID selector and an attribute selector, the styles defined by the ID selector will be applied.

Example: ID vs Attribute Selectors

#unique-element {
  background-color: yellow;
}

[id="unique-element"] {
  background-color: green;
}

The element with the ID "unique-element" will have a yellow background because the ID selector has higher specificity.

Contextual selectors are more specific than a single element selector

Contextual selectors, which target elements based on their relationship to other elements, have a higher specificity than a single element selector.

Example: Contextual Selectors

div {
  font-size: 16px;
}

div p {
  font-size: 14px;
}

Paragraphs inside a <div> will have a font size of 14px, while other <div> elements will have a font size of 16px.

The universal selector has low specificity

The universal selector (*), which targets all elements, has a very low specificity. It has a specificity value of (0, 0, 0, 0), which means that any other selector will override its styles.

Example: Universal Selector

* {
  margin: 0;
  padding: 0;
}

p {
  margin: 10px;
}

All paragraphs will have a margin of 10px, overriding the universal selector's margin of 0.

Inherited values have low specificity

Inherited values, which are passed down from parent elements to their children, have a specificity value of (0, 0, 0, 0). This means that any directly applied style will override an inherited value.

Example: Inherited Values

body {
  color: black;
}

p {
  color: blue;
}

Paragraphs will have a color of blue, overriding the inherited black color from the <body> element.

The !important Exception

In CSS, the !important declaration overrides the normal specificity rules. When !important is used, it gives the declared style the highest priority, regardless of its selector's specificity.

How !important overrides other specificity values

When you add !important to a style declaration, it overrides any other conflicting styles for that property, even if the conflicting selector has a higher specificity value.

Specificity override example

#unique-element {
  background-color: yellow;
}

.class-name {
  background-color: blue !important;
}

The element with the ID #unique-element will have a blue background, despite the ID selector having a higher specificity than the class selector. This is because the !important declaration overrides the specificity hierarchy.

When to use !important

While !important can be useful in certain situations, it should be used sparingly, as it can make your CSS harder to maintain and debug. Here are a few cases where using !important might be justified:

Case Explanation
Overriding inline styles If you need to override inline styles applied directly to an element, using !important can be a quick solution.
Overriding styles from third-party libraries When working with third-party CSS libraries, you might need to use !important to override their styles to match your design.
Creating utility classes If you are creating utility classes that should always take precedence, such as a class for hiding elements, using !important can make sure that the styles are applied consistently.