UX Design and Development course

Minimizing depth & selector performance

In writing any CSS rules, the compelling case to dominate selector specificity is always there. Be it by closely mirroring the DOM structure and/or over specifying a class selector with a DOM element.

OOCSS and SMACSS teach us that falling into these all too common traps are to be avoided at all costs. But what are the costs? What are the alternatives?

Do not mimmic the DOM

A common pitfall with many CSS developers is the overwhelming urge to mimmic the DOM in order to lock in specificity of the CSS rule.

.contact-list div ul li > li p {
  font-weight: bold;
}

This style of coding will nail the staying of the p tag, but there are some issues.

  1. From reading the code, there is no apparent reasoning as to why all the content in this p tag is being made bold
  2. Tying the CSS rules specifically to the HTML structure …
    1. reduces portability
    2. replication of style means duplication of rule
    3. fragility of code means inability to edit markup without breaking style

Reduce selector depth

Refactoring the previous example, I would want to remove all the selectors that are not absolutely needed for this rule to be effective.

The name of the selector .contact-list of course is necessary. The only other part that jumps out at me is the child selector relationship between the li tags.

.contact-list li > li p {
  font-weight: bold;
}

This is a good start, but still much too dependent on the HTML structure never changing. Instead of relying on the HTML selectors alone, I would try to add more semantic meaning to these selectors.

Be more semantic in application

Looking at the previous example, .contact-list is literally a very well named module. Reading the code, it is easy to assume that all CSS Rules contained within will pertain to the contact list module in the application.

It is the use of the decedent selectors in the DOM that troubles me. The previous examples greatly reduce reusability, readability and portability.

To address these issues, I would suggest acknowledging the nature of the sub-modules contained within the .contact-list module.

Let's imagine that at the point of the fist li, this is where a list of .contacts will appear. Then our code would look like this.

.contact-list .contacts > li p {
  font-weight: bold;
}

It's getting better. Inside our list of .contacts is an individual .contact. But our code is stating that it wants to target the first li thereby stating that there will be a number of li's in this module. So, ok. Instead of trying to dynamically point to the first li, lets give it a name, like .contact. And since it is the only one in this block, we do not need to use the inefficient decedent specifier of >.

.contact-list .contacts .contact p {
  font-weight: bold;
}

It's getting better. Now looking at this code, do we really need to be so specific as to the parental relationship between .contacts and .contact? I would argue no. All we really need is to state that any p tag in a .contact module is to be bold.

.contact-list .contact p {
  font-weight: bold;
}

It's getting better. But looking at this again, is this bold font-weight so absolutely specific to .contact-list and .contact that we need nest these selectors? Again, I would argue no.

I would think that we could make .contact a module that stands on it's own.

.contact p {
  font-weight: bold;
}

OOCSS says to extend in the DOM

Now it is here that we can split hairs. OOCSS argues that this font-weight is a purely presentational object that we should be applying in our DOM.

.bold-type {
  font-weight: bold;
}

Then our HTML example would then contain the appropriate CSS class in the DOM.

<div class="contact-list">
  <div class="">
    <ul class="contacts">
      <li class="contact">
        <p class="bold-type"></p>
      </li>
      <li class=""></li>
    </ul>
  </div>
</div>

Some will argue that this is class'itus. But this process will make your CSS and HTML easier to read as there are clearer instructions as to what is happening. This will also allow the CSS selectors to be much shallower and much more universal in application.

Who knows, next you may end up creating a series of .contacts inside a .directory list. And you never know, that directory may use <ol> versus <ul> for SEO purposes.

The point is we don't know and we should never assume we do and we should never restrict future development by locking it all in a box to be clever.

Extending in CSS

OOCSS says to extend in the DOM. This is a pretty good trick and well received by many front-end developers. But there is also the argument that we are sacrificing the cleanliness of the DOM For the sake of the CSS. This is a cake and eat it too issue. CSS supports extending and has done so for years. So, why don't we use this more often?

Using the previous example, let's take the opportunity to refactor once again. First we decided that this example was going to lead to unnecessary duplication of the font-weight rule.

.contact p {
  font-weight: bold;
}

So we created a OOCSS class that we can then use in the DOM.

.bold-type {
  font-weight: bold;
}

We can combine these ideas into a single use case where we will keep the .bold-type as a OOCSS class, but not use it in the DOM. What we will do is extend this to our specific instance.

.bold-type, .contact p {
  font-weight: bold;
}

This method gives us the best of both worlds. Not only does it create the OOCSS selector that can be used in the DOM, but also binds the same CSS rule to the new selector without duplicating the rule.

Over qualified selectors

While this is a feature of CSS, I feel that it should be generally avoided.

For example, let's say I have a class like .selected and I over qualify it with a p tag.

p.is-selected {
  font-weight: bold;
}

Writing selectors such as p.is-selected are unnecessary and in most cases it's preferred to remove the element name from the selector. This will reduce the size of the CSS as well as improve the selector performance by not requiring the class to match the element.

Removing the element name will also loosen the unnecessary relationship between your CSS and HTML. This will allow you to be more universal in application of the class without needing to update the CSS.

Where this is considered acceptable is when the element name causes the class to behave differently.

p.is-selected {
  font-weight: bold;
}

li.is-selected {
  border-color: red;
}

I consider this to be a poor practice and prefer to be more explicit in my rule creation. This style of writing also creates an unnecessary dependency on strict application of the rule. If applied to any other element, this rule then will not work.

There are a couple of other ways to address this same situation that are easer to read and permanent as well.

SMACSS teaches us that it is preferred to have a is-active State Rule attributed to each element in the DOM as it is specifically modified. By this rule, if there are multiple elements within a module that require modifications based on interactivity, then we could use the selector of the module itself and create an adjoining class rule.

.button { … }
.button.is-active {
 …
}

.list { … }
.list.is-active {
  …
}

selector.class is not a naming convention

But why do people use these? Elementary my dear Watson. Many developers will use over qualified selectors as a naming convention. jQuery UI really lead the way with this. I can't emphasize enough how much this is a bad idea.

For example, let's say that you have the class of .nav and in your UI you want to reuse this and base it's style off of it's application to the DOM. So there are rules for div.nav and ul.nav and ol.nav.

This tells absolutely nothing about what these selectors are doing in the UI. Are they primary nav modules? Secondary nav? Or even site nav for that matter. It could be navigation to external resources, or a list of previously viewed items. The point is that these names associated to a specific selector in the DOM has no meaning at all.

Not only is this inefficient and hard to read, this technique also locks the CSS selector to a specific use case in the DOM. ol.nav can only be applied to ol tags. What happens when you need to apply that same module style to a ul?

So, ul.nav looks like this … and ol.nav looks like that … So if I want ol to look like ul then I need either copy or extend the styles from ul into another selector and apply that to the DOM element.

Specificity becomes a real issue here. So it is typical to see these rules either copied of extended into an ID as this is the sledge hammer of CSS. And to be devil's advocate here, since there is no real naming strategy before, why make one now? After all, the definition you are giving it is ul.nav, so that's it's name. And #ul-nav is born. ;(

<ol class="nav" id="ul-nav"></ol>

While these techniques technically will work, these are poor practices and lead to more confusion versus adding value to the project.