1

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.

Community
  • 1
  • 1
Tom
  • 4,835
  • 3
  • 35
  • 49

2 Answers2

2

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.

BoltClock
  • 630,065
  • 150
  • 1,295
  • 1,284
  • In the absence of any other rules, font settings applied to `.dropdown` would cascade down to all interior elements. The fact is that I wish *all* text nodes within the dropdown to use a font-size of 14px, not just text nodes that happen to be inside As inside LIs. This is the issue I mentioned about proliferation of natively-styled areas peripheral to my explicitly styled areas. But, setting aside our differences re: best practices, my analysis of selector specificity tells me that my broad rule should trump the narrow native rule, and it's not clear to me that you have shown otherwise. – Tom Sep 20 '13 at 16:07
  • 1
    @Tom: I missed that bit about applying the font size to text nodes, sorry. In that case, you have an easy solution: create another rule `body#myid .mt-site-nav .quick-more .dropdown li a { font-size: 1em; }` and it'll inherit (not cascade) the 14-pixel size from your existing rule. – BoltClock Sep 20 '13 at 16:12
  • 1
    @Tom: As for specificity, the key sentence is, "Since each selector is matching a different element, specificity does not come into play." In other words, specificity is only relevant when you have more than one rule targeting the exact same element, which is not the case here. – BoltClock Sep 20 '13 at 16:17
  • So, your analysis is that I'm trying to apply font-sizing through inheritance, and that tactic is being overridden by a targeted selector that has no explicit rivals. That makes sense. And I like your `1em` approach; couldn't I use `inherit` as well? A little unclear on the difference between cascading and inheriting, now, but I'll look them up. – Tom Sep 20 '13 at 18:05
  • 1
    @Tom: Yes, you could. The term "cascading" is really counter-intuitive, but [this part of the spec](http://www.w3.org/TR/CSS21/cascade.html) sums up each one nicely. – BoltClock Sep 20 '13 at 18:10
  • Simple `inherit` didn't quite work: MT sets font-size on both the LI (11px) and the A (12px). I wrote rules targeting each with `inherit` and `1em`, and both worked. Thanks for helping me figure this out. – Tom Sep 20 '13 at 18:18
1

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.

michaelward82
  • 4,064
  • 21
  • 35
  • I never knew we had some specificity calculator. Great – Akshay Khandelwal Sep 20 '13 at 15:10
  • @Tom also referenced a specificity calculator in his question when he wrote "[calculated](http://specificity.keegan.st/)" – Dylan Holmes Sep 20 '13 at 15:16
  • So he did (not sure if I missed that or whether it appeared with an edit) – michaelward82 Sep 20 '13 at 15:17
  • Is it just me or is that calculator bugged? Why is it counting pseudo-classes and pseudo-elements the same? `.class:pseudo-class::pseudo-element` reports as (0, 0, 1, 2) on Firefox on my PC when it should be (0, 0, 2, 1). – BoltClock Sep 20 '13 at 15:22
  • I've changed the link to the one that Tom linked to. – michaelward82 Sep 20 '13 at 15:25
  • @michaelward82: I checked the native rule and corrected my OP to match; their rule is written correctly, matching your syntax. Also, I should point out that I cannot edit the native rules, so if it were the case that faulty native code were to blame, I'd have to work around it. Thanks for the attention to detail, though. 8) – Tom Sep 20 '13 at 16:01