Precedence in CSS selector specifity conflicts (type vs class selector)
Asked Answered
D

2

6

I learned about selector precedence from this tutorial. I have trouble understanding the behavior of this in one case. I have an element in HTML:

<input class="top_bar_login_form_input" type="text"  name="email" placeholder="Prijavno ime">

The problem is that properties from another selector override the properties from the class.

Picture

As shown in the picture above the class gets overridden by a less specific selector. The element gets selected by input[type="text"], which is less specific than a class. The only reasoning behind these behavior that I see is that the .inputbox class is also calculated in determining the precedence, even though it doesn't match the element.

Why does the type selector override the class selector?

Doorman answered 2/2, 2013 at 21:13 Comment(3)
Are you going to ask a question?Feat
@keyboardSmasher: you smashed him too :DEnthymeme
I wanted to understand why a type selector overrides a class, I will edit my post.Doorman
S
11

TL;DR Answer

The first rule is more specific than the second one because it has both a type and attribute part for the selector, and thus has precedence:

input[type="text"] { }         /* type + attribute for specificity */
.top_bar_login_form_input { }  /* only class for specificity, so *less* specificity */

Longer answer

You'd think that the type="text" bit, which is an attribute selector, is more specific than a class selector, in accordance with the MDN page on specificity:

The following list of selectors is by increasing specificity:

  • Universal selectors
  • Type selectors
  • Class selectors
  • Attributes selectors
  • Pseudo-classes
  • ID selectors
  • Inline style

The above quote was in the MDN article at the time this answer was written.

Why that is misleading:

(Tanks to @BoltClock's insights.)

The above only seems correct, but that's because you typically include the element in the selector (e.g. input[type="text"]) when doing an attribute selector. However, what's sneaky: the input bit matters.

Suppose we have the following markup:

<input class="my-class" type="text" value="some value" />

In the following scenario the input renders red:

[type="text"] { color: green; }
.my-class { color: red; }             /* last rule matched */

If we reverse the rules in a scenario, the input will render green:

.my-class { color: red; }
[type="text"] { color: green; }       /* last rule matched */

This is because both selectors have equal specificity. Now introducing the input selector to the attribute rule will make one of them more specific, which can be seen in this scenario:

input[type="text"] { color: green; }  /* most _specific_ rule matched */
.my-class { color: red; }

The W3 spec makes my head hurt, but it does have the details on why the above works. See also the answer by @BoltClock and comments in those code examples for info on how the specificity is calculated.

Scree answered 2/2, 2013 at 21:21 Comment(11)
Are all the browsers the same in evaluating specifity?Doorman
Hmmm... I've experienced quite a few cross-browser (i.e. IE) difficulties with CSS, but not with specificity as far as I can recall. (Note: I've blocked IE6 from memory, and IE7 is fading too...)Scree
Do note that not every browser has equal support for selectors. See for example the quirksmode overview.Scree
Sorry, but this is where MDN is flat-out wrong... classes, attributes and pseudo-classes are all equally specific. See my answer for the real reason why the selectors are behaving this way.Awlwort
@Borut Flis: IE6 treats chained classes in a series .A.B.C the same as the last class selector .C so it has a weight of only 1 class. Other browsers will correctly count 3 classes. That's just about the only difference I'm aware of, but that's not relevant here.Awlwort
@Awlwort Thanks for pointing that out, learned something new there! I tried to fix my answer while keeping the link and quote to MDN. Could you comment on whether I fixed things now (or suggest edits if it still needs work)?Scree
@Awlwort Lol, you upvoted back then, even though before the edit from just now it almost seemed I "blamed" you for the wrong answer :D. Mea culpa, now corrected!Scree
what about input[class="my-class"] vs input[type="text"]?Fontana
@SoursopTree What about that comparison?Scree
which one take the precedence?Fontana
@SoursopTree Easy to test, is it not? ;-)Scree
A
7

Your element is matching input[type="text"] in the first rule. Although the .inputbox selectors don't match it, that doesn't affect precedence because a comma-separated list of selectors only counts by the most specific selector in the list that does match an element. If none of the selectors match it then it doesn't count at all.

The reason why the first rule overrides the second is because class selectors and attribute selectors have equal specificity. The input type selector accompanying (or accompanied by) the attribute selector is what causes it to outweigh the lone class selector:

/* 1 attribute, 1 type -> specificity = 0-1-1 */
input[type="text"]

/* 1 class             -> specificity = 0-1-0 */
.top_bar_login_form_input

So it's the first selector being more specific than the second, and not the other way around.

If you qualify the class selector with a type so you have input.top_bar_login_form_input, the selectors will be balanced and your second rule will override the first.

Awlwort answered 3/2, 2013 at 5:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.