Search code examples
csscss-specificity

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.


Solution

  • 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.