Tom
Tom

Reputation: 9127

CSS selector specificity comparison

I'm restyling a third-party platform (MindTouch 4). While doing so, I'm trying to declare all the various styling properties as broadly as possible, to prevent the unintentional proliferation of natively-styled areas on the page.

The platform has a custom SELECT control, using markup like this:

<div class="mt-site-nav">
    ...
    <span class="quick-more">
        <span class="drop-link">Current Value</span>
        <ul class="dropdown">
            <li>
                <a href="...">Option 1</a>
            </li>

            <li>
                <a href="...">Option 2</a>
            </li>
        </ul>
    </span>
</div>

I wish to style the option text with font-size 14px; the native default is 12px.

So, I wrote this CSS rule:

body#myid .mt-site-nav .quick-more .dropdown { font-size: 14px; }

However, their native rule still wins when rendering the links in the menu:

@media screen { .dropdown li a { font-size: 12px; } }

In Chrome, I can see that both rules are considered when rendering links in the menu, but their rule (which is declared earlier than mine) wins. I was confused by this, since I thought I had a pretty good handle on specificity. So, I checked my understanding of the rules and manually calculated the weight of both rules.

Mine has specificity 0131 (0 inline style, 1 ID, 3 classes, 1 element name).

Native has specificity 0032 (0 inline style, 0 IDs, 1 class, 2 element names). (I am uncertain how to calculate the contribution of the media selector in the native rule.)

I don't care what base you're using for your math, "0131" is greater than "0032". So, my rule should win.

Yes, I could easily duplicate the element chain that appears in the native rule (i.e. ".dropdown li a"), but I think that's a fragile approach, and I feel it's important to set styling properties as broadly as possible, to facilitate scalability and as a preventative against native styling peeking out between the cracks.

Any help sorting this out is appreciated. I obviously have workable alternatives, so what I'm asking for here is an academic explanation of how these two rules fare in CSS weighting systems.

Thanks very much.

Upvotes: 1

Views: 992

Answers (2)

BoltClock
BoltClock

Reputation: 723448

The subject of your selector is .dropdown:

body#myid .mt-site-nav .quick-more .dropdown

The subject of the selector within the @media screen rule is a:

.dropdown li a

Since each selector is matching a different element, specificity does not come into play. Your rule applies to the .dropdown element, and the native default applies to the a elements inside it. That's why you see that both rules are being applied. And since the font-size values are in pixels, the a elements will continue to have a 12-pixel font size.

Duplicating the li a portion is not fragile; it's a proper solution (if not the only one) to this sort of problem. Cascading happens on a per-element basis, and if you're not dealing with relative values or inheritance, then targeting the wrong elements isn't going to work as you expect.

Also, screen is a media type (and more extensively a media query), not a selector, and @media rules do not affect the cascade other than to enable or disable the rules inside them depending on whether the media applies to the browser.

Upvotes: 2

michaelward82
michaelward82

Reputation: 4736

As far as I am aware, the correct syntax for the media query is:

@media screen { .dropdown li a { font-size: 12px; } }

This should solve your problem.

See these fiddles, the first uses the correct media query syntax:

http://jsfiddle.net/SE6fP/

The next uses the incorrect syntax used by your example

http://jsfiddle.net/SE6fP/1/


In additon, here is a little on CSS specifity for anyone who isn't sure how it works:

CSS specifity follows a ruleset and produces a score for each selector.

There are calculator tools available which will explain the specifity value for any give rule.

http://www.w3.org/TR/CSS21/cascade.html#specificity says that the following rules are used:

A selector's specificity is calculated as follows:

  • count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)

The specificity is based only on the form of the selector. In particular, a selector of the form "[id=p33]" is counted as an attribute selector (a=0, b=0, c=1, d=0), even if the id attribute is defined as an "ID" in the source document's DTD.

Upvotes: 1

Related Questions