jsgroove
jsgroove

Reputation: 1497

CSS class and descendant selectors practices

I would like to form a better understanding of when it is appropriate to use classes to target content as opposed to other available options, specifically, descendant selectors.

In many cases, instead of using classes, it is possible to use descendant selectors to target the same elements. If the same thing can be accomplished in both ways, what is the logic between deciding an option ?

Here are some example scenarios:

1.

a.

<div class="main">
     <div>
         <div> /* target */
             <div></div>
         </div>
     </div>
</div>

.main > div > div

b.

<div class="main">
     <div>
         <div class="content">
             <div></div>
         </div>
     </div>
</div>

.content

2.

a.

<div class="main">
     <div> /* target */
        <div></div>
     </div>
     <div> /* target */
        <div></div>
     </div>
</div>

.main > div:first-child
.main > div:last-child

b.

<div class="main">
     <div class="content1">
        <div></div>
     </div>
     <div class="content2">
        <div></div>
     </div>
</div>

.content1
.content2

3.

a.

<div class="main">
     <div>
         <div></div>
         <div></div>
         <div></div>
     </div>
</div>

.main > div div

b.

<div class="main">
     <div class="content">
         <div></div>
         <div></div>
         <div></div>
     </div>
</div>

.content div

What is the logic between deciding to use classes or descendant selectors ?

Upvotes: 9

Views: 17719

Answers (3)

fncomp
fncomp

Reputation: 6178

To get the conversation started on the right foot checkout What is a good CSS strategy?. Personally, I think the @gregnostic's strategies should be renamed to domains.

As I see it, every project with more than a a dozen webpages really needs to implement the various domains to certain degrees based on their scope.

The domains here being (ordered by specificity):

Resetting

Attempts to achieve a baseline across browsers and environmental conditions. Made famous by Eric Meyer. A lot of people skip over this as a solved problem, but as someone who works on an on page Content Management system, believe me CSS resetting is important and can be a challenging problem to solve gracefully (esp. if the client is using the same theme library as you are).

These selectors should be as general as possible. Picking based on CSS classes doesn't normally make any sense, except, on occasion, when you need to reset inside a given shell.

Layout

Potential page structures, often handled by a grid system of some sort. These should be a little more specific, but ought to rely on some sort of recursive pattern. Something like:

.row {
    width: 100%;
    min-height: 30px;
} 

.row .col {
    width: 100%;
}

    .row.two .col {
        width: 50%;
    }

While this can be done with tag selection, I find it's almost never intuitive for the next person and you always wind up with a grid magically appearing in the wrong place. Using classes helps keep the Junk drawerTM smaller. For a full scale implementation see:

Component/Functional

I tend to get very specific on these. One of my favorite patterns for this is Stubornella's OOCSS. The basic concept is that in order to minimize duplicate code you bundle attributes inside of various CSS selectors and do your best to make them play nice together. A simple example of this is Twitter Bootstrap's buttons.

While you might be able to fudge in child selectors here, I'd strongly recommend against it as the first time someone wants to change:

<button type="button"></button>

to:

<button type="button">
    <span class="ugly-orange-bordered-purple-thing">
        My Button
    </span>       
</button>

The overly general:

button {
    border: 99em purple dotted;
}

Will totally conflict with:

.ugly-orange-bordered-purple-thing {
    border: 5em orange dashed;
    background-color: purple;
}

However, if you change button to .btn then you can simply moved that to the span or just left off.

Typography

Handling the appropriate display of various fonts under given conditions. I always handle this element selector to the extent possible. I usually kick it off with something like:

h1, h2, h3, h4, h5, h6 {
    font-family: sans-serif;
}

p, span, a, ... {
    font-family: serif; /* Or whatever. */
}

h1 {
    font-size: 2em;
}

h2 {
    font-size: 1.8em;
}

... 

.row h2 {
    font-size: 1.6em;
}

Depending on the need of the client, I might even add in rules for spans inside of buttons.

Theme

Much like the Typography domain, I tend toward tag selection a lot more in this area. Theme's are almost by definition throw away (since e.g., Taco Bell and Mc Donald's don't want to have the same theme).

The Dojo toolkit has some nice examples of setting up themes as a separate layer (checkout nihilo). They tend toward classes here, but that's mainly for re-usability, which I already discussed.

Junk drawer

The junk drawer of CSS, hopefully most of this is contained inside <!--[if lt IE 9]>, but every project has these and they should go in last. Keeping this empty is a priority, but it's not as important as getting the job done (something I keep trying to remind myself).

I make these really specific, since the last thing you want is to change the a rule like:

div div {
    white-space: nowrap;
}

on a nearly complete site. Wherever possible, I put these in a work place friendly "legacy" area.

Closing notes

  • When I do code reviews that have CSS in them, Junk drawer is the only place I want to see an id without a really good explanation.
  • Like all other code, always attempt to follow the patterns of the surrounding code (unless it makes you eyes bleed).
  • Let me know if I missed something

Upvotes: 11

bfavaretto
bfavaretto

Reputation: 71908

It all depends on the rest of your markup. Consider this modified version of your 1.a example:

<div class="main">
     <div>
         <div> /* target */
             <div></div>
         </div>
     </div>
     <div>
         <div> /* target? */
             <div></div>
         </div>
     </div>
</div>

Selector .main > div > div would select both divs, which may or may not be what you want. So sometimes you have to be more specific, adding classes and ids to the markup, and tweaking the selectors accordingly.

There are multiple ways to select the same elements with CSS, not just one "correct" way. It's usually not recommended to be too specific, but too general selectors can cause problems too. You have to find a balance, and you only get there by practicing, there's no recipe.

Upvotes: 0

vpiTriumph
vpiTriumph

Reputation: 3166

Descendant selectors allow you to avoid embedding class information in your html. This may be convenient when the wrapping block is a logical container. For example, if you have constructed a table using div tags and you have hundreds, or thousands, of rows you could potentially cut down your document size, and increase readability, by specifying a descendant style instead of specifying class='...' repeatedly.

  <div class='mytable'>
    <div></div>
    <div></div>
    <!-- A LOT MORE ROWS -->
  </div>

The advantage of specifying a class is that you aren't tied to a particular ordering. It can be extremely frustrating having to alter your descendant tags each time you want to rearrange your view. The other nice thing about specifying a class is that when working with CSS, it's far easier to search for a specific class name than have to decipher your descendant blocks.

To my knowledge, there aren't black & white guidelines as far as when each is appropriate. Use your own discretion and consider the benefits/shortfalls of each as you design.

Upvotes: 6

Related Questions