CodeinWP CodeinWP

When to Avoid the Descendant Selector

Those of us who have started using modular or object-oriented CSS principles have learned to avoid, as much as possible, the use of the descendant selector (or, more accurately, the descendant combinator).

A selector that uses the descendant combinator looks like this:

.sidebar p  {
    color: hotpink;
    font-size: 3em;
}

Everything you see before the opening curly brace is the selector. The combinator in this case is the space character. There are other combinators, too. But in this case, the selector uses the descendant combinator.

Now that we have a technical understanding of the selector itself, let’s discuss what to keep in mind when deciding to use this selector.

Why is the Descendant Selector Restrictive?

To understand why the descendant selector can cause problems, look at the example I used above. Those styles are limited not only to paragraph elements, but on paragraph elements that are children of an element with a class of “sidebar”.

That’s pretty strict. This limits what you can do with those styles. You can’t reuse those styles, so they’re basically stuck in that context.

This is outlined in the OOCSS wiki, when discussing the separation of “container and content”.

Does OOCSS Discourage Use of the Descendant Selector?

This question is covered in the OOCSS FAQ. Part of the answer there reads:

No–descendant selectors are not discouraged, but putting them too high in the DOM tree is.

So the idea here is that you avoid the descendant selector where it will cause unnecessary restrictions, specifically “high in the DOM tree”. But you shouldn’t avoid it altogether (as I’m sure many of us have discovered, since it’s impractical not to use it at all).

Nicole Sullivan’s media object is a good example of an OOCSS module that uses the descendant selector abundantly, but not in a restrictive manner.

So, by all means, use the descendant combinator in your selectors. But avoid examples like the following:

.header p { }
.container div { }
.sidebar h2 { }

In these examples, which are using elements high up on the DOM tree, these styles are not reusable, so they could unnecessarily bloat your code.

No Dogma Here

These are suggestions, not dogma. I realize that not every project and circumstance is the same. So do whatever you need to do to solve your current coding problems.

If that means using some of the principles of modular CSS, then go for it. Even if you’re not too strict about these rules, I think keeping in mind the spirit behind them will make you a better CSS developer in the long run.

31 Responses

  1. Scott says:

    I thought for OO-CSS it was preferred to do things like .media-img (and apply that class to the image tag) instead of .media img. Alternatively, the child selector works well, e.g. .media>img since the img must be a direct child anyway.

    Pretty much the only time I use a descendent selector nowadays is for tables. Writing something like .table-class > tbody > tr > td is pretty laborious and ugly, .table-class td is way simpler.

  2. Sarah says:

    I think I’m missing something here. Can’t this style

    
    .sidebar p  {
        color: hotpink;
        font-size: 3em;
    }
    

    be re-used simply by adding another selector to it, like this?

    
    .sidebar p,
    .footer p  {
        color: hotpink;
        font-size: 3em;
    }
    
    • lord xeon says:

      excatly, there is nothing wrong with using

      .sidebar p {
          color: hotpink;
          font-size: 3em;
      }

      It the assumption that every single style you write will be reused 7 times on the same website that is wrong. I might have a sidebar, where the paragraphs are 100% different from everywhere else on every other page on my site. There can be 1, or 700 paragraphs in my sidebar, but they all need to look the same outrageous way.

      I do think you should listen to the last few lines though:

      These are suggestions, not dogma. I realize that not every project and circumstance is the same. So do whatever you need to do to solve your current coding problems.

      Just cause someone says to not use the descendant selector, or IDs doesn’t mean you have to listen to them.

      I hope I didn’t come across as mean spirited.

    • Yes, of course you can do that, but if you ever change one of those to look different from the other, then you’ll have to separate them anyways. Or you could add a new class to one of them.

      But even better is to style all your paragraph elements to look the same, starting from a base style, so you’ll do this:

      
      p  {
          color: hotpink;
          font-size: 3em;
      }
      

      And then build from there, adding any extending classes as needed.

  3. Paul Irish says:

    I’m glad you don’t mention performance. Old advice indicates the selector is slow. It’s not. It’s very very fast. :)

  4. Yuppy Soul says:

    Sorry if I’m missing something here but what exactly

    If we are using

    
    .sidebar p  {  
            color: hotpink;  
            font-size: 3em;  
    }  
    

    My HTML looks like this

    
    <div class="sidebar">
    <p>Tweet</p>
    ... a bunch more tweets
    </div>
    

    If i’m taking out the p what exactly is the alternative we are proposing here? Surely not adding classes to all the P tags?

    
    .foo  {  
            color: hotpink;  
            font-size: 3em;  
    }  
    
    
    <p class="foo">Tweet</p>
    <p class="foo">Tweet</p>
    <p class="foo">Tweet</p>
    <p class="foo">Tweet</p>
    

    Now my HTML is polluted with a bunch of classes I don't need.

    What did I miss here?

    • Richard says:

      I’m with you on this. What’s the proper alternative then?

    • What you want to focus on is styling all <p> elements the same, wherever they are. Generally speaking, there shouldn’t be a big difference between a paragraph in the sidebar compared to elsewhere.

      So you start with all paragraphs styled the same, using:

      
      p {
        /* whatever */
      }
      

      And then build from there, adding a class to any paragraph that needs to be styled differently.

      Of course, if you do need sidebar paragraphs to have really different styles, then I wonder if maybe you just need an extra wrapper or something to do that with.

      But, all that being said, I might decide to use the descendant selector in that case, too. I would just plan things from the beginning to try to style all the paragraphs the same and then build from there. I’m not dogmatic about avoiding the descendant selector, but I’m just pointing out that it can restrict your stylesheets.

      • Pablo Rincon says:

        “Generally speaking, there shouldn’t be a big difference between a paragraph in the sidebar compared to elsewhere.”

        I think that is more a problem related to Design, if we have different sections with different styles, descendant selectors are the best way to go.

        Even if you go:

        
        p{color:#000; ...}
        

        To properly segment it, you will have to use descendant selectors.

        In other words I do not see your point about not using this.

        • Or add a class to the ones that will be different. It all depends. I never said to avoid them, I just encouraged good planning.

          The main point of the article was to avoid them high up in the DOM tree, not avoid them altogether. Using them with something like .sidebar p might be fine, but before you do that, I would start with base styles and work from there, rather than jumping straight to .sidebar p, or something even more specific.

          • Wes Towers says:

            Hey, Louis. After reading your article, which basically taught me that I should stay away from descendant selectors way up high in my DOM tree, I saw the point reiterated here in your comment and I was glad for being right with the lesson I learned. I am more of a web and graphic designer than a programmer so I don’t really get everything there is about coding except the basics. But, that does not mean that I don’t love learning stuff such as this. So, thank you. Now, I know what to point out to my programmer if I see problems related to the use of descendant selectors.

      • Yuppy Soul says:

        I’m lost again.
        You are suggesting to me that anything doesn’t use the plain P should have a class? So then I should use class=”foo” on every p? If not, I’m not understanding something.

        If I have say a blog of course I start with

        
        p{color:grey}
        

        I’m using this already to define my base style. It doesn’t help me define style my tweets in my sidebar. My tweets want to be blue (or whatever).

        “What you want to focus on is styling all elements the same, wherever they are. Generally speaking, there shouldn’t be a big difference between a paragraph in the sidebar compared to elsewhere”

        Why not? Talk about restricting stylesheets, now P tags in different sections shouldn’t have big differences? why not?

        No one is saying you are dogmatic, but the point is you are suggesting polluting the HTML with a bunch of unnecessary (as far as I can see) classes and I haven’t seen what your reasoning is.

        Thanks

        • In the case you’re citing, it would not be:

          
          .sidebar p { }
          

          It would be something like:

          
          .tweet p { }
          

          And that would still be inside the large sidebar. So this goes back to the original point of the article. In the article, I said to avoid the descendant selector high on the DOM tree. Those individual tweets would not be high up on the DOM tree, so you could use the descendant selector in that case.

          But if it’s just an odd paragraph or two in the sidebar, then you’re better off using a class to distinguish “other” paragraphs. Then you can use that style anywhere, not just in the sidebar.

          Most likely, you will have another wrapper like an unordered list or something else you can hook onto anyhow, so using .sidebar p would, in many cases, be unnecessary.

          Do you understand what I’m saying now?

          Another thing I think is thrown around a lot is the idea of (as you put it) “polluting” the HTML. This concept of “clean, presentation-free HTML” is (IMHO) blown out of proportion. I understand you might feel differently, and I respect that. But there really is no practical benefit to “clean” HTML, as I see it. As I said, do whatever you think works for you. But recognize that something like .sidebar p can be very restricting since you can likely use another wrapper instead that is much further down in the HTML tree.

          Also, please don’t look at the CSS on this site, because you’ll see me breaking all these rules. :))

          • Yuppy Soul says:

            Ok, I was writing a big long thing in reply to this but it became to complex and doing html examples in this forum is a bit frusrating.

            I think the main problem is your assumption that everyone is using OO principles when using CSS.

            The thing is I’m not buying it. It’s pretty ironic that you seem to excuse me of wanting some Utopian ‘clean’ HTML. Yeah, I want it clean but clean doesn’t mean sterilised. There’s a big difference between having a wardrobe sitting in the corner of my room and having 7 or them lined up there. I have no vision of a wardrobe-less room.

            This is the problem I see with OO-CSS. It attempts to shoehorn in a tried and tested methodically from one place to another. This is a typical programmer thing. They hate change and different ways of doing things.

            CSS is not Object-Oriented. Part of CSS’s power is the cascade. sticking classes everywhere and not using the cascade seems pretty dogmatic.

            The reason I didn’t understand what you were saying is because you give an example which is total theory. Put that in the real world and it doesn’t look so good.

            Example

            .sidebar p {
                color: chucknorris;
            }
            
            
            <div class="sidebar">
            
            <p>arst</p>
            <p>...</p>
            <p>...</p>
            <p>...</p>
            <p>...</p>
            <p>...</p>
            <p>...</p>
            
             </div>
            

            I see this as a good (if simplified) example of a real world thing. The HTML is ‘clean’ (again – not meaning free from classes) and the CSS is perfectly maintainable. When chucknorris changes to hotpink there’s no issue with changing that.

            I’m not ‘restricted’ like you keep saying. My CSS is tailored to it’s need (as it should be). It’s a bit of a fantasy to think I’m going to make this into some amazing re usable module that’s forever maintainable anywhere.

            The alternative is this

            <div>
            
            
            <p class="sidebar">arst</p>
            <p class="sidebar">...</p>
            <p class="sidebar">...</p>
            <p class="sidebar">...</p>
            <p class="sidebar">...</p>
            <p class="sidebar">...</p>
            <p class="sidebar">...</p>
            
             </div>
            

            leaving aside whether the name sidebar works for the name now we have all this unnecessary crap in the HTML and our maintainable hasn’t gone up.

            If you have a better alternative let me know.

            It did seem however from your other replies that you agree this is the alternative.

            If it is, surely ‘Avoid the Descendant Selector’ would seem like bad advice when this is the alternative?

          • Yuppy Soul,

            The article does not say “avoid the descendant selector”. In fact, the whole purpose of this article was to dispel the notion that OOCSS discourages use of the descendant selector. It doesn’t. The advice from an OOCSS viewpoint is to “avoid” it “high up on the DOM tree”.

            Therefore, you definitely should use the descendant selector — but you should do your best to avoid it high up on the DOM tree.

            Now, you provided an example that you claim is “real world”. But I cannot get any context from your example. You haven’t shown me the full HTML so I can see if in fact your “sidebar” is high or low on the DOM tree.

            The reason that I used a theoretical “sidebar” element to discourage descendant selector use is because, generally speaking, the “sidebar” element is usually very high up on the DOM tree, on the same level as “main” or “header”.

            If this is the case in your example, then your code example is very unrealistic. But if your example is just a small callout box or something, then it’s fine — you can use the descendant selector in that case.

            In other words, if the paragraph elements in your examples are in fact direct children of the “sidebar” element, and there are no other elements in that sidebar, then it’s fine, use it there, it’s not a problem.

            But in most cases, it would not be correct to use something like “sidebar p” because there would always be an intermediate element to hook on to instead.

            Finally, I should point out that nobody that promotes OOCSS thinks it’s really “object oriented” in the programming sense. The word “object” is not a programming word, it’s a word that references … well… “objects”, which can be anything. It’s not limited to actual programming.

            Anyhow, no disrespect intended by my responses. I really don’t think you and I disagree on this, I think you’re just not getting the purpose of my original article which explains that you should still use the descendant selector, just don’t use it high on the DOM tree.

  5. Yuppy Soul says:

    Thanks for your reply. Hopefully my replies don’t come across as trying to provoke an argument.

    I was thinking about showing the full DOM but to be honest it was getting a pain to be escaping so many angle brackets.

    You are right, this is actually where the confusion came in for me. I understood you only want to avoid it high up the tree. The thing is I don’t understand why you think that’s important.

    It doesn’t make a difference whether I’m high on the DOM or not as far as I can see. What matters is you know where you are in the DOM.

    Let’s say I have this.

    
    <div class="sidebar">
    <p>...</p>
    <div class="tweets">
    ...
    </div>
    
    <div class="related">
    <p>...</p>
    ...
    </div>
    
    </div>
    <>
    

    I’m in a different place on the tree but my CSS is the same, it doesn’t matter if I’m 10 levels deeper or one from the body like the sidebar.

    As you say, you should use the intermediate hook of .tweets and not .sidebar. I’m totally with you, and I wasn’t suggesting otherwise. but if there are no intermediate hooks, it’s totally fine to use .sidebar as far as I can see.

    
    .tweets p{color: chucknorris}
    

    I’m not sure what you think is unrealistic about just having p’s in the sidebar.

    “In other words, if the paragraph elements in your examples are in fact direct children of the “sidebar” element, and there are no other elements in that sidebar, then it’s fine, use it there, it’s not a problem.”

    ok, so that was basically my whole point. I don’t need to be ‘avoiding’ it just because it’s high up the tree.

    If OO-CSS has nothing to do with OOP, well frankly it’s badly labelled. OOP is based around objects. If you aren’t basing your OO-CSS on objects in what sense is it Object Oriented?

    Don’t worry, I didn’t take your comments as disrespectful. I can’t imagine what the comments would like if this was youtube.

  6. Dan Freeman says:

    I don’t get this at all. You say to avoid these:

    
    .header p { }  
    .container div { }  
    .sidebar h2 { }  
    

    What’s the proper way to style an H2 in the sidebar? You say it’s not re-usable, but it shouldn’t be.

    • In many cases, you won’t have H2s different in the sidebar, they might be the same as all other H2s. But if they are different, you have a few other options.

      1) Use a class on any different H2s. I know this seems wrong, but it’s not as restricting, and now you can use that class on another H2.

      or

      2) Use a closer parent element. See my discussion above with Yuppy Soul. It’s extremely unlikely that “sidebar” would be the closest ancestor element. If it is, then it’s fine, use .sidebar h2. The key is not to use any of your really big elements that make up major parts of your layout. Again, see the discussion above where I clarify this further.

  7. tibolan says:

    I’m agree with Louis.
    If we are talking about a site, build in team, with project hazard, with contributors you don’t know, with full-powered customer, IMHO this advice is good.

    If you are mastering all the decision and the process, and think it’s OK for you to use this type of selector, no problem (furthermore Paul said that’s very fast ).

    But it you ever had to refactoring HTML and css cause brief changed, cause a block was added in this sidebar (as I have so often to do …) you maybe will follow this way of thinking the css.

    A developer who need to create sturdiness day by day.

  8. For those who are still scratching their heads wondering why something like .sidebar p is not good practice, I’ve built a rough demo of what I’m talking about:

    http://jsbin.com/odazit/1/edit

    You can see in this example that I have paragraphs in different areas of this mock website. I want a few of those paragraphs to have slightly different styles. So those have a unique class. None of those paragraph styles are dependent on location. I can put an alternative paragraph anywhere I want, and it will look the same.

    But you might ask, What if I want all the paragraphs in the sidebar to look the same, and yet different from all others outside of the sidebar? Well, besides the fact that this is an unrealistic scenario, even if it is true, then I wouldn’t use the sidebar as the hook for the descendant, but rather, I’d use one of the sidebar modules instead.

    This is the point I was trying to explain above. The sidebar in this example is high on the DOM tree, so there is no point in doing aside p when I can instead do .side-module p.

    It’s true, it might be equally unrealistic to need to reuse the styles in aside p, but this is not just about a sidebar. It’s about a way of thinking about your code better in all areas. So instead of always reaching for high-DOM descendants in your selectors, I’m trying to encourage a more modular approach that doesn’t trap styles in contexts that don’t exist anywhere else in your pages.

  9. Heydon says:

    Don’t go blaming the descendant combinator, Louis!

    It’s the class that restricts the styling contexts of “p” and, without the class, the combinator – acting as intermediary – wouldn’t have to be dragged into the sordid affair.

    As you point out elsewhere in the comments, a simple “p” selector is optimal. It is the manufacture of the class that wrecks it. Ironic, given OOCSS’s love affair with the class attribute.

    Thanks for a provocative post :-)

    • I agree. Always start with the naked element type selector (like “p” or “h1”) and only add a class if you are extending what it can do for certain elements. Of course, some generic elements (like div or section) probably don’t need any generic styles, but it all depends on the situation.

  10. Mike says:

    I wanted to dive into this article specifically because I’m a bit obsessed with optimization (front-end), but like many others I can’t seem to get fully on board with this approach. I’d much rather use a .sidebar p { // styles } than add a bunch of classes in my HTML. It’s a much more optimized approach to keeping markup clean, with styles still being easy to parse.

    Two other areas where I depart from thinking this is a good approach is with unique design, and building it atop a CMS. Many of my designs (and many others, of course) use different styles for common selectors (h2, p, a, etc.) depending on where those selectors sit on the page. A blockquote’s p element should look far different than a normal p element, meaning I’ll have blockquote p { // styles } in my stylesheet. No way around it except if I chose to bloat my HTML with styles.

    But on this second point, I’m often developing atop WordPress where I don’t have direct access to the classes in, say, the sidebar’s p or h2 elements. Perhaps there’s a hook in WP to allow me to add classes to all p elements in the sidebar, but I certainly wouldn’t want to add more server-side processing to something so easily accomplished with CSS descendant selectors.

    • blockquote p is very low on the DOM tree, so that’s fine to use. I use it myself, and would recommend others to use it, too. I think too many people in the comments here are missing the point of this post. It’s not discouraging the descendant selector; it’s discouraging its use high on the DOM tree. Have I said that enough? :)

      Your other example regarding WordPress goes back to what I mentioned in at least one other comment: The fact that sidebar p is not the only way to target paragraphs in a sidebar. Look, for example, at the Twenty Twelve theme. If you inspect the source, you’ll see that in the sidebar element (which uses #secondary), each section of the sidebar is in a smaller section called .widget. So in that case, you could just do .widget p, which is much lower on the DOM tree.

      But more than likely, you won’t have very many paragraph elements in that type of sidebar anyhow, and even if you do, you’ll always have another closer ancestor element to hook onto, rather than the large sidebar.

      I hate to say it, but all the comments arguing against .sidebar p are simply impractical and do not represent what actually occurs on real web pages and what’s possible in the HTML tree.

      • Yuppy Soul says:

        It doesn’t matter if you think my example is ‘realistic’ or not. I can construct my HTML in any way that I want. You have no way of knowing what my app / page has a need for.

        It may be true that in most scenarios you may not want to do it, but again that’s irrelevant to me. My example is perfectly valid and usable, saying it’s unrealistic doesn’t validate your argument. You need more than that.

        Having said that, this may just frankly come down to semantics. I’m not liking this use of the word ‘avoid’. I prefer a positive look where we encourage people to question these things and think about why we do these things.

        This whole idea doesn’t help me write better css or think more about it,

        As I believe you mentioned in another comment the point is about using the closest ancestor element, or however you phrased it. I completely agree with that and I think it’s an excellent concept to have people understand.

        The whole DOM tree thing just seems like a red herring.

  11. Loughlin. says:

    I think this is a load of barmy old cack to be honest. I’ve been developing websites for 12 years now and I have still to come across one that has a paragraph style that is 100% consistent across the many pages that usually make up even a small site. paragraphs have different fonts, colours, margins, borders, padding etc dependent on their context and the overall aesthetic design of the page. Articles like these, while well written and dripping with good intentions, remind me of the days back in 2005 when people used to put those W3C XHTML and CSS validated buttons in the footer of their websites.

    Who cares? Does avoid descendent selectors make a difference to the browser’s performance, the user’s experience or the cosmos? I would argue it does not. All it does it make the planning phase of the front end of a web project become tediously restrictive as you try to design your pages using p and H1-H6 tags that try to follow a common style.

    This kind of nonsense makes my blood boil:

    “What you want to focus on is styling all <p> elements the same, wherever they are”

    and of course this one which makes me want to poke my eyes out with a red hot poker:

    “Generally speaking, there shouldn’t be a big difference between a paragraph in the sidebar compared to elsewhere”

    • I’m sorry, but if your paragraphs look drastically different in the sidebar as compared to a regular paragraph, then you’re doing one of two things wrong:

      1) You’re styling the paragraph when you should in fact be styling a wrapper element
      2) You’re using the wrong element

      I never said the paragraphs would look exactly the same, or be “100% consistent”; I said there would not be a big difference. There would be different styles, certainly, but those can be done by adding a class that extends or adds to the initial styles on all paragraphs. It’s much cleaner that way and the benefit is more maintainable code.

      Also, I never said or implied that there was any difference from a browser or user perspective. The point of this suggestion is to help code be more maintainable and less bloated, especially for large projects. This is from a developer perspective, not a user/browser perspective.

  12. I recommend never used decedent selectors for paragraph or character styles because print design programs have proven the maintenance benefits of separating text presentation from code architecture. It’s just easier to maintain on average if you can cut and paste text from anywhere to anywhere without having it look different because it’s moved in the dom. If you’re using the DOM architecture to create a cluster of type positioned for meaning such as a large dollar price leading a cents price in much smaller font or a picture with a caption, then it’s still better performance and maintenance to avoid descendant selectors according to high performance website design book I read.

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).