Did CSS Specificity trouble you? Not anymore🚀

Introduction

A commonly heard phrase while working with front-end devs, I'm applying this property but it's not getting applied. This is because of a lack of understanding of CSS specificity. It is a crucial topic every front-end developer should master to outshine their work. This post will help you to be aware of all aspects of CSS specificity and in the future, you will be able to handle and debug any specificity-related bugs In much reduced time.

What is CSS Specificity?

Specificity in CSS is a set of rules that determines which styles take precedence when there are conflicting style instructions for the same web element. Specificity helps the browser figure out what styles to apply and which to ignore. It's a bit like deciding what outfit wins in a fashion showdown, ensuring that the webpage looks the way you want by giving priority to certain styling instructions over others.

Power distribution

!important > Origin > Specificity > Position

!important

CSS declaration !important overrides any other declarations within the same cascade layer and origin.

 <p id="paragraph">This is a paragraph. color should always be blue</p>
p#paragraph {
  color: blue !important;
}

Origin

  1. Author styles: These are the styles advocated by the webpage developer.

  2. User styles: The End Users custom styles for specific web pages.

  3. User Agent stylesheet: These are browser-inbuilt styles that are cascaded if there are no specific styles applied to a particular element.

Specificity

selector specificity can be denoted as (W, X, Y, Z)

  1. W stands for Inline-style where styles is defined within the HTML tag, this will have the highest specificity.
    <h1 style="color: blueviolet;">This and example for inline style</h1>

selector specificity will be (1, 0, 0, 0) because we have one inline style.

  1. X stands for ID selector where styles applied using an ID selector this will override styles applied with lower specificity. ID selector has second highest specificity after inline styles.
    <div id="example-id">This an example  for Id selector</div>
#example-id{
  color: blue;
  font-size: 24px;
  border: 1px solid red;
}

selector specificity will be (0, 1, 0, 0) because we have one ID selector.

  1. Y stands for class selector like .myClass, attribute selectors like [type="radio"] and [target="_blank"], and pseudo-classes, such as :hover, :nth-of-type(3n), and :required this classes have lesser specificity than ID selector but greater than type selectors.
<h1 class="myclass">Example for class selector</h1>
.myclass{
            font-size: 16px;
            color: red;
            background-color: blueviolet;
        }
 .myclass:hover{
            font-size: 24px;
            color: blue;
            background-color: pink;
            padding: 8px;
        }

The .myclass selector specificity will be (0, 0, 1, 0) and .myclass:hover specificity will be (0, 0, 2, 0) because we have 2 classes .myclass and :hover pseudo-class therefore (0, 0, 2, 0) will win.

  1. Z stands for type selectors like h1, div, span, p, body, nav, and pseudo-elements like ::after, ::before, ::placeholder this have least specificity.
        <h1>This is a example for header1</h1>
        <span>This is a span example for span </span>
        <div>This is a example for div</div>
        <body>This will be container body</body>
        <input type="text" placeholder="Enter your name">
         h1 {
            color: yellow;
            background: magenta;
            margin: 8px;

        }
        span {
            color: brown;
            padding: 4px;
            font-size: 8px;
        }
        div {
            font-size: 16px;
            color: royalblue;
            padding: 16px;
        }
        body {
            margin: 16px;
            padding: 8px;
            background-color: chocolate;
        }
        input::placeholder{
            color: red;
            font-size: 12px;
        }

here in the above examples all types will have selector specificity as (0, 0, 0, 1) except input::placeholder because it has one type input and one pseudo type ::placeholder thus combining it will be (0, 0, 0, 2).

Cascade Engine Evaluation

 (W, X, Y, Z)
(1, 0, 0, 0) wins over (0,4,8,6)
(0, 1, 0, 0) wins over (0,0,6,8)
(0, 0, 0, 2) wins over (0,0,0,1)
(0, 2, 6, 5) wins over (0,2,6,0)

The cascade engine evaluates these factors to make conclusive decisions on style application, ensuring that the styles with higher importance, specificity, and source order are prioritized in rendering web elements.

Specificity Examples

 Example 1
<button id="btn-id" class="btn-class">Button</button>
/* (0, 1, 0, 0) - #btn-id wins over class selector */ 
 #btn-id{
                font-size: 16px;
                background-color: brown;
            }

 /* (0, 0, 2, 0) */
   .btn-class:hover{
                font-size: 32px;
                background-color: blanchedalmond;
                border: 2px solid greenyellow;
            }

The :is(), :not(), and :has() exceptions

These pseudo-classes alone don't have any weightage on specificity calculation but when they are passed with arguments then those arguments will be haveing the specificity;

.my-class:is() {
/*(0, 0, 1, 0) - is() don't have any weightage*/
}

li:is(:nth-of-type(2n+3)){
/*(0, 0, 1, 1) - :nth-of-type(2n+3) inside :is() contributes to class*/
}

Helper points

  1. Using !important exceptions is not a good practice, adjust the specificity and try to achieve the outcome. Keep !important as the last option.

  2. Duplicating id or classes is the best way to increase the specificity.

/*(0, 4, 0, 1) - higher number of high specificity selector makes it more specific
#id-repeat #id-repeat #id-repeat #id-repeat div {
color: red;
}