Search code examples
htmlcss

Why does an attribute selector have higher specificity than a class?


Why does the input[type=number] selector in the example below override the .num class selector? Shouldn't both have a specificity of 1?

My expectation was that whichever was declared later would have overridden the former.

input {
  width: 100px;
}

input[type=number] {
  border: 2px solid green;
}

.num {
  border: 2px solid red;
}
<input type="number" class="num"> Why is the border not red (as requested by .num)?


Solution

  • Attribute selectors share the same level of specificity as CSS class selectors. In your example you have input[type=number] and .num.

    • input[type=number] has a specificity of 0 0 1 1, it has two selectors in it, an element input and attribute [type=number].
    • .num, has a specificity of 0 0 1 0 and only has one selector in it, a class.

    Since input[type=number] has a higher specificity than .num it's style will always win out regardless of placement. If input[type=number] was changed to [type=number], then placement would play a role as they'd both share a specificity of 0 0 1 0 and the latter would win out.

    input {
      padding: 0.25em 0.5em;
    }
    
    /* Specificity - 0, 0, 1, 1 */
    input[type="number"] {
      border-style: dotted;
    }
    
    /* Specificity - 0, 0, 1, 0 */
    [type="number"] {
      border: 1px dashed indianred;
    }
    
    /* Specificity - 0, 0, 1, 0 */
    .num {
      border-color: rebeccapurple;
    }
    
    /* Specificity - 0, 0, 1, 0 */
    [type="number"] {
      border-style: solid;
      border-width: 2px;
    }
    <input type="number" class="num" name="number" value="0">

    * Note: I only used the same CSS selector twice for demonstration purposes. Notice which border-style wins out. Although there was an attempt to apply dashed and solid after dotted, neither was applied because of specificity. The cascade, which rule(s) came after another, is applied when specificity values are identical.