Mastering CSS Specificity: Understanding the Algorithm and Effective Tag Selection Methods

·

12 min read

Let’s say ,I am working on a web development project and structured the application using html , now you should style html page. so you started styling the page , give style for the button red, button class green, and button id orange. you expect the color on screen to show green ,but you get the orange. If you get to see this kind of behavior and enable to fix ,then you need to learn the Specificity Algorithm

Specificity Algorithm : CSS is a set of rules that browsers use to determine which styles are applied to an element when multiple rules match. It's calculated based on the types of selectors used in your CSS.

1. Understanding Specificity

Specificity is represented as a four-part value:

css(A, B, C, D)
  • A (Inline Styles): Inline styles (e.g., style="color: red;") always have the highest specificity and are counted as 1.

  • B (IDs): The number of id selectors in a rule.

  • C (Classes, Attributes, Pseudo-classes): The number of .class, [attribute], and :pseudo-class selectors.

  • D (Elements, Pseudo-elements): The number of element and ::pseudo-element selectors.

2. How Specificity is Calculated

The specificity of a selector is based on its components:

  • Inline styles: (1,0,0,0)

  • ID selectors: (0,1,0,0)

  • Classes, attributes, pseudo-classes: (0,0,1,0)

  • Element and pseudo-element selectors: (0,0,0,1)

When comparing specificity:

  1. Compare A. If equal, move to B.

  2. If B is equal, move to C.

  3. If C is equal, move to D.


3. Examples of Specificity

SelectorSpecificity
* Universal(0,0,0,0)
div tag(0,0,0,1)
p::before(0,0,0,2)
.class class(0,0,1,0)
[type="text"] attribute(0,0,1,0)
:hover pseudo element(0,0,1,0)
#id id(0,1,0,0)
style="color: red;" inline style(1,0,0,0)
#id.class:hover id class pseudo all in one element(0,1,2,0)
div#id.class[type="text"]:hover tag id class attribute pseudo in one element(0,1,3,1)

4. Specificity in Combined Selectors

4.1 Multiple Selectors

When multiple selectors are combined, specificity adds up:

/* Specificity: (0,1,3,1) */
div#main.container[data-type="example"]:hover::before {
  color: blue;
}

4.2 Universal Selector (*)

The universal selector does not add to specificity:

* {
  color: black; /* Specificity: (0,0,0,0) */
}

4.3 Combinators

Combinators (e.g., +, >, ~) do not affect specificity:

div > p {
  color: red; /* Specificity: (0,0,0,2) */
}

4.4 :not()

The :not() pseudo-class does not add specificity for its argument:

div:not(.special) {  /** it wiil not applay the css to the .specal class*/
  color: green; /* Specificity: (0,0,1,1) */
}

4.5 Group Selectors

In grouped selectors, each selector is evaluated independently:

h1, #main {
  color: purple; /* Specificity: (0,1,0,0) for #main, (0,0,0,1) for h1 */
}

5. Corner Cases in Specificity

5.1 Inline Styles vs. External CSS

Inline styles always win, regardless of other rules:

<div id="example" style="color: red;"></div>

5.2 !important

The !important declaration overrides specificity rules but respects the cascade (order of appearance):

div {
  color: green !important;
}
#main {
  color: blue; /* Ignored because of !important */
}

5.3 CSS Variables

CSS variables inherit specificity from where they are declared:

:root {
  --main-color: blue;
}

5.4 Overriding with Inheritance

Inherited properties (e.g., color, font) do not affect specificity:

body {
  color: black; /* Inherited */
}
p {
  color: green; /* Overrides inherited color */
}

5.5 Cascading with Equal Specificity

When two rules have equal specificity, the last one declared wins:

div {
  color: red;
}
div {
  color: blue; /* Wins due to cascade order */
}

Universal selectors (*), combinators (+, >, ~), and negation pseudo-classes (:not(),**:**root,:hover,etc..) do not affect specificity.

Pseudo elements

pseudo-element allows you to insert content before the content of an element. It is often used for adding decorative elements or text that is not part of the document's source HTML.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Pseudo-Class Examples</title>
  <style>

      :root{
         --main-color: red;
      }
    /* Example for :hover */
    button:hover {
      background-color: lightblue;
      cursor: pointer;
      color:var(--main-color);
    }

    /* Example for :active | works on clicking */
    button:active {
      transform: scale(0.98);
      background-color: darkblue;
      color: white;
    }

    /* Example for :focus | on the input typing*/
    input:focus {
      border: 2px solid green;
      outline: none;
    }

    /* Example for :focus-visible | used while navigating on tab button in browser */
    button:focus-visible {
      outline: 2px dashed red;
    }

    /* Example for :visited */
    a:visited {
      color: purple;
    }

    /* Example for :link */
    a:link {
      color: blue;
      text-decoration: none;
    }
  </style>
</head>
<body>
  <h1>Pseudo-Class Examples</h1>

  <!-- Hover and Active Example -->
  <button style="padding: 10px 20px; font-size: 16px;">Hover or Click Me</button>

  <!-- Focus Example -->
  <div style="margin: 20px 0;">
    <input type="text" placeholder="Focus on me" style="padding: 10px; font-size: 16px;">
  </div>

  <!-- Visited and Link Example -->
  <div>
    <a href="https://www.example.com" target="_blank">Unvisited Link</a>
    <br>
    <a href="https//google.com" target="_blank">Visited Link</a>
  </div>
</body>
</html>

Combinators

CSS combinators are used to define relationships between elements. They target specific elements based on their position or relationship to other elements in the document. Here’s a breakdown of combinators, their use cases, and examples with inline CSS (where possible) or embedded CSS.


1. Adjacent Sibling Combinator (+)

  • Selects an element that is immediately after another specified element.

Example:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Adjacent Sibling Combinator (+)</title>
  <style>
    h1 + p {
      color: blue;
      font-style: italic;
    }
  </style>
</head>
<body>
  <h1>This is a heading</h1>
  <p>This paragraph is immediately after the heading and will be styled.</p>
  <p>This paragraph is not immediately after the heading and won’t be styled.</p>
</body>
</html>

Explanation:

  • The h1 + p rule styles only the first paragraph after the <h1>. Other <p> elements are not affected.

2. Child Combinator (>)

  • Selects elements that are direct children of a specified parent.

Example:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Child Combinator (>)</title>
  <style>
    div > p {
      background-color: lightgreen;
      padding: 10px;
    }
  </style>
</head>
<body>
  <div>
    <p>This is a direct child of the div and will be styled.</p>
    <div>
      <p>This is a descendant but not a direct child and won’t be styled.</p>
    </div>
  </div>
</body>
</html>

Explanation:

  • The div > p rule applies only to <p> elements that are direct children of <div>.

3. General Sibling Combinator (~)

  • Selects elements that are siblings of a specified element and appear after it in the DOM.

Example:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>General Sibling Combinator (~)</title>
  <style>
    h1 ~ p {
      color: darkorange;
      border: 1px dashed darkorange;
      padding: 5px;
    }
  </style>
</head>
<body>
  <h1>This is a heading</h1>
  <p>This paragraph is a sibling of the heading and will be styled.</p>
  <p>This paragraph is another sibling and will also be styled.</p>
  <div>
    <p>This paragraph is inside a div and won’t be styled.</p>
  </div></html>

Explanation:

  • The h1 ~ p rule applies to all <p> elements that are siblings of <h1> and come after it.

Summary Table of Combinators

CombinatorSelector SyntaxDescription
AdjacentA + BTargets B that is immediately after A.
ChildA > BTargets B that is a direct child of A.
General SiblingA ~ BTargets all B siblings of A that follow A.

Universal selector

it will select every thing represented by *

Summary

1. CSS Specificity

CSS specificity determines which styles are applied to an element when multiple rules target the same element. The specificity value is calculated based on a hierarchy:

Specificity is calculated as follows:

  • Inline Styles: 1000

  • IDs: 100

  • Classes, Pseudo-classes, and Attribute selectors: 10

  • Elements (tag selectors) and Pseudo-elements: 1

Specificity Hierarchy:

  • Inline Styles: style="..." – Highest specificity

  • IDs: #id

  • Classes, Pseudo-classes, and Attribute Selectors: .class, :hover, [type="text"]

  • Elements and Pseudo-elements: div, p, ::before

Example:

#main { color: red; }   /* Specificity: 100 (ID) */
h1 { color: blue; }     /* Specificity: 1 (Element) */
button:hover { color: green; } /* Specificity: 10 (Pseudo-class) */

2. Types of Selectors

  • Universal Selector (*): Selects all elements.

      * { color: red; }
    
  • Type Selector (Element Selector): Selects elements by their tag name.

      p { font-size: 16px; }
    
  • Class Selector (.): Selects elements with a specific class.

      .btn { background-color: blue; }
    
  • ID Selector (#): Selects elements with a specific ID.

      #header { font-weight: bold; }
    
  • Attribute Selector ([]): Selects elements with a specific attribute.

      input[type="text"] { background-color: yellow; }
    
  • Pseudo-class Selector (:): Selects elements in a specific state.

      a:hover { color: green; }
    
  • Pseudo-element Selector (::): Targets specific parts of elements.

      p::first-letter { font-size: 2em; }
    
  • Descendant Selector (space): Selects elements that are descendants of another.

      div p { color: blue; }
    
  • Child Selector (>): Selects direct children of an element.

      div > p { color: red; }
    
  • Adjacent Sibling Selector (+): Selects an element that is immediately after a specific element.

      h1 + p { color: green; }
    
  • General Sibling Selector (~): Selects all elements that are siblings of a specific element.

      h1 ~ p { color: orange; }
    

3. CSS Combinators

  • Descendant (space): Selects all elements that are descendants of a specific element.

      div p { color: red; }
    
    • Matches <p> inside a <div>, regardless of depth.
  • Child (>): Selects only direct children of a specified element.

      div > p { color: blue; }
    
    • Matches <p> only if it's a direct child of <div>.
  • Adjacent Sibling (+): Selects the next sibling of a specified element.

      h1 + p { color: green; }
    
    • Matches the first <p> that follows directly after an <h1>.
  • General Sibling (~): Selects all siblings following a specific element.

      h1 ~ p { color: orange; }
    
    • Matches all <p> siblings after an <h1>.

4. Ways to Select Elements

By Tag Name (Element Selector)

  • Example: div {} – Selects all <div> elements.

By Class Name

  • Example: .btn {} – Selects all elements with class btn.

By ID

  • Example: #header {} – Selects the element with the ID header.

By Attribute

  • Example: [type="text"] {} – Selects all elements with the type="text" attribute.

    • Example: [href*="example"] {} – Selects all elements whose href contains "example".

By Pseudo-classes

  • :hover – Selects elements when hovered.

      a:hover { color: green; }
    
  • :first-child – Selects the first child of its parent.

      div > p:first-child { font-size: 20px; }
    
  • :last-child – Selects the last child of its parent.

      div > p:last-child { font-size: 20px; }
    
  • :nth-child(n) – Selects the nth child of a parent.

      div > p:nth-child(2) { font-weight: bold; }
    
  • :not() – Excludes a specific element.

      div:not(.special) { color: red; }
    

By Pseudo-elements

  • ::before – Inserts content before an element.

      p::before { content: "Note: "; font-weight: bold; }
    
  • ::after – Inserts content after an element.

      p::after { content: ";"; }
    
  • ::first-letter – Styles the first letter of an element.

      p::first-letter { font-size: 2em; }
    

5. Universal Selector (*)

  • Selects all elements.

      * { margin: 0; padding: 0; box-sizing: border-box; }
    

6. Combining Selectors

  • Multiple Selectors: Apply the same style to multiple elements.

      h1, h2, h3 { color: blue; }
    
  • Grouping Selectors: Combine similar selectors to reduce repetition.

      .btn, .link { text-decoration: none; color: black; }
    

7. Specificity Rules Recap

  • Inline styles have the highest specificity.

  • ID selectors have a higher specificity than class, attribute, or pseudo-class selectors.

  • Class, attribute, and pseudo-class selectors have a higher specificity than element and pseudo-element selectors.

  • Specificity is calculated by adding the points for each type (e.g., 100 for IDs, 10 for classes).


8. Inheritance

Some properties are inherited by child elements, like color and font-family. To prevent inheritance, use inherit or initial values.

  • Inheritable properties: color, font-family, line-height, etc.

  • Non-inheritable properties: padding, margin, width, etc.


9. Specificity Example

#header { color: red; }     /* ID selector */
.btn { color: blue; }       /* Class selector */
p { color: green; }         /* Element selector */

If a <p> element has both a class btn and is inside an ID header, the color will be red because the ID selector (#header) has the highest specificity.


10. Cascade Order

CSS rules are applied based on:

  1. Importance (e.g., !important)

  2. Specificity (see above)

  3. Source Order (the last defined rule takes precedence if selectors have the same specificity)


11. What is div#id.class[type="text"]:hover?

This is a complex CSS selector combining multiple selector types to target a specific element.

Breakdown:

  • div: Targets a div element.

  • #id: Matches a div with a specific ID.

  • .class: Matches a div with a specific class.

  • [type="text"]: Matches a div that has an attribute type with the value text.

  • :hover: Applies styles when the user hovers over the div.

Full Selector Meaning:

It selects a div that:

  1. Has a specific id.

  2. Has a specific class.

  3. Has an attribute type with the value "text".

  4. Is hovered over by the user.

Example:

htmlCopyEdit<div id="example" class="highlight" type="text">
  Hover over me!
</div>
cssCopyEditdiv#example.highlight[type="text"]:hover {
  background-color: lightblue;
  color: darkblue;
}

Behavior:

  • When you hover over the div, its background turns light blue, and the text color becomes dark blue.

Why Use Complex Selectors?

  1. Granular Targeting: Allows precise control over styles.

  2. Contextual Styling: Targets elements based on specific states or attributes.

  3. Avoid Clashes: Reduces the chance of accidental style overrides in large projects.


Advanced Example with Explanations

<div id="login" class="form-item" type="text">
  Username
</div>
<div id="password" class="form-item" type="password">
  Password
</div>
/* Specific styling for hovered text input */
div#login.form-item[type="text"]:hover {
  border: 2px solid green;
}

/* General styling for all form items */
div.form-item {
  padding: 10px;
  background-color: #f9f9f9;
}

Explanation:

  1. The first rule applies only to the div with id="login", class="form-item", and type="text" when hovered. It adds a green border.

  2. The second rule applies to all div elements with the form-item class, giving them padding and a light background.