Search code examples
htmlcssbuttondisabled-control

CSS button:disabled doesn't apply to buttons previously styled by id


In both Chrome and Firefox on Windows I have come across this behavior. Button colors are styled by id and by class, then I use a global button:disabled rule to set that color to gray. All the buttons whose non-disabled color is set via a class-based rule are properly styled when disabled, but those styled by an id-based rule are unaffected by the button:disabled.

button {
  font-size:2rem;
  width:3rem;
}
#a { 
  color:red; 
}
.b {
  color:green;
}
#c, #d {
  color:blue; 
}
button:disabled, #c:disabled {
  color:gray;
}
<button id="a" class="a" disabled>A</button>
<button id="b" class="b" disabled>B</button>
<button id="c" class="c" disabled>C</button>
<button id="d" class="d">D</button>

Button A, styled by id, has red text in spite of the global button:disabled rule.

Button B, styled by class, is properly styled by the button:disabled rule.

Button C is properly styled, but it requires a separate #c:disabled rule.

Button D is the only one that is not disabled, for comparison purposes.

Is this a feature or a bug? If it's a feature, can someone please explain it? I would automatically consider it a bug if it weren't for the fact that the behavior is consistent across two major browsers.


Solution

  • It is not a bug.

    They are obeying the three column values and comparison rules. See https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity#specifications

    In particular

    The selector with the greater value in the ID column wins no matter what the values are in the other columns.

    In general, the comparison is done by column 1 first, and if there is a winner there the other columns don’t come into it.

    Then the second column is considered and likewise if there is a winner, the third column is not considered.

    Looking at the selectors used in the question:

    An id puts a 1 in the first column.

    The class adds a 1 to the second column.

    The pseudo class :disabled adds a 1 to the second column.

    The type button adds a 1 to the third column.

    The #a therefore has a 1 in the first column and this beats anything in the second and third columns, thus that element has color red.

    For the #c that will have weight 1-0-0 as well but that will be beaten by the 1-1-0 of the #c:disabled.

    Note that the button:disabled is weaker at 0-1-1.

    The cascading order only comes into play if there are two selectors with the same weight, then the one that comes afterwards wins.