Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 ?

like image 872
jsgroove Avatar asked Apr 20 '12 00:04

jsgroove


People also ask

What is descendant selector and class selector?

A descendant selector is made up of two or more selectors separated by white space. A descendant selector of the form " A B " matches when an element B is an arbitrary descendant of some ancestor element A .

What are descendant selectors in CSS?

A descendant selector in CSS is any selector with white space between two selectors without a combinator. Here's some examples: ul li { } header h2 { } footer a { } .module div { } #info-toggle span { } div dl dt a { } Take ul li { } for example. It means “any list item that is a descendant of an unordered list.”

What is the purpose of descendant selectors?

The descendant selector is a way to select elements that are located somewhere underneath other elements, according to the tree structure of the webpage. This selector is actually multiple selectors combined together, but separated by a space.


2 Answers

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:

  • 960 Grid System
  • Twitter Bootstrap
  • Columnal
  • Tons of others.

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
like image 61
fncomp Avatar answered Sep 18 '22 20:09

fncomp


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.

like image 28
vpiTriumph Avatar answered Sep 19 '22 20:09

vpiTriumph