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.
2
Answers
In CSS, more specific rules override less specific ones. Basically, an id selector is more specific than a class selector, which is more specific than a type selector. More details here.
What I would do is to put the
button:disabled
rule up the top just under thebutton
rule, to cater for all buttons without specific styling. Then for any buttons where I want a different color, append:not(:disabled)
to the selector.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
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.