skip to Main Content

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


  1. 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 the button 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.

    button {
      font-size: 2rem;
      width: 3rem;
      color: green;
    }
    
    button:disabled {
      color: gray;
    }
    
    #a1:not(:disabled), #a2:not(:disabled) { 
      color: red; 
    }
    
    .b:not(:disabled) { 
      color: blue; 
    }
    <button id="a1" class="a">A</button>
    <button id="b1" class="b">B</button>
    <button id="c1" class="c">C</button>
    <button id="a2" class="a" disabled>A</button>
    <button id="b2" class="b" disabled>B</button>
    <button id="c2" class="c" disabled>C</button>
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search