Chapter 7. Applying ECSS

In this Chapter we are going to cover the following topics:

ECSS is a good match for complex web applications. First up, let’s consider how we might apply ECSS around the logic of a large application.

Applying ECSS to logic modules

Typically, in a web application, some programming language (e.g. JavaScript/TypeScript/Ruby/whatever), will be generating ‘a thing’.

It’s often practical and desirable to use the file name of that thing as the name of the module (or component of a module) that is generates. Therefore, if a file is called ‘Header.js’ and generates the container for the header, any component parts of that header could be named accordingly. For example, in ECSS parlance, a company registration number might get sw-Header_Reg as its class. By extension, a search box component inside the header might have classes like sw-HeaderSearch_Input (the input box created by the HeaderSearch.js file).

An example

Let’s consider a more concrete example. Suppose we are authoring a JavaScript client-side application and we have a JavaScript component called ‘ShoppingCartLines.js’. Its task is to render out the lines within a shopping cart and it in turn displays within a module called ‘ShoppingCart.js’. The ‘ShoppingCart’ module renders out anything to do with the shopping cart itself. Straight forward enough so far.

Now let’s complicate our imagined scenario a little by suggesting that our shopping cart will work within a modal view in some scenarios and as part of the page, in normal document flow, in others.

In this instance, we have a wider module: ‘ShoppingCart’ and a component that typically lives within the module called ‘ShoppingCartLines’. Each of those will have their own child nodes. The module and component have two possible views: in a modal and in the page. Let’s also imagine that the switch of contexts would be handled by the application logic.

Our constant is the module itself and we can use a namespace to provide context for it. When applying ECSS around application logic it makes sense to always use the full name of the application module or component as the module section of the ECSS style selector. This has the benefit of making all HTML classes in the DOM self descriptive as to their origin and purpose.

OK, so, at this point, our selectors could be named like this in the style sheets:

.mod-ShoppingCart {} /*Modal*/
.page-ShoppingCart {} /*Page*/
.mod-ShoppingCartLines {} /*Modal*/
.page-ShoppingCartLines {} /*Page*/

This way our module and component have their two contexts isolated by a namespace switch. We are free to style each as we see fit with no potential leakage of styles from one to the other. This is the exact kind of scenario that typically becomes fraught when components and modules share HTML classes in the interest of abstraction and re-use.

Let's consider a twist on this scenario. Let's suppose we don't switch contexts with application logic. Instead, we have a switch of styles with media queries. We have a modal implementation at smaller viewports and the page style, in normal document flow, at larger viewports.

In this instance, we could have a single namespace e.g. sc-ShoppingCart (I'm using sc- to designate the context is 'ShoppingCart') and use media queries in the CSS to provide visual changes.

For example:

.sc-ShoppingCart {
    /*Modal styles for smaller viewports*/
    @media (min-width: $M) {
        /* Page styles for larger viewports */
    }
}

.sc-ShoppingCartLines {
    /* Modal styles for smaller viewports */
    @media (min-width: $M) {
        /* Page styles for larger viewports */
    }
}

Child nodes of a module or component

As mentioned previously, a module or component will have its own child node elements. These selectors should be named with a child extension. For example:

.sc-ShoppingCart {
    /* The root of the component/module, no child extension needed */
}

.sc-ShoppingCart_Title {
    /* The 'title' child node of the Shopping Cart */
}

.sc-ShoppingCart_Close {
    /* A 'close' button child of the Shopping Cart for when the cart is modal */
}

Each child gets the namespace and component (or module) name of its parent.

So, at this point we now have an understanding of how we might name our selectors when applying ECSS around application modules and logic. We will look now at how we might name selectors and apply ECSS around purely visual modules. However, first a brief but important tangent on using type selectors.

A note on type selectors

When authoring CSS, there are occasions when it can be tempting to use type selectors. Typically, when there are inline level, seemingly innocuous nodes such as <i>, <b>, <em> or <span>. For example, suppose we have a sentence with a couple of words that need to be bold. Then temptation would be to do this:

And use these selectors to apply styles to the contents of that b tag:

There are a couple of problems here:

  1. We have created a dependency on certain markup (it must be a child node and be a b tag).
  2. Due to point 1, we have created a selector that is more specific than it needs to be. This makes any future overrides more difficult to reason about and perform.

While it may seem overly verbose, this is how that scenario should be handled:

<p class="ch-ShoppingCart_TextIntro">Here is the contents of your cart. You currently have <b class="ch-ShoppingCart_TextIntroStrong">5 items</b>.</p>

And this CSS:

.ch-ShoppingCart_TextIntro {
    /* Styles for the text */
}

.ch-ShoppingCart_TextIntroStrong {
    /* Styles for the bold section within */
}

Each element has its own selector and rule. Neither depends upon the other. Neither rule requires particular markup to be applied.

Applying ECSS to visual modules

'Visual' components refers to areas of markup that are not necessarily generated by a particular piece of application logic.

You can still break areas into logical visual areas and apply ECSS to them. This is the approach employed on the http://ecss.io website.

There are no hard and fast rules. As an example, we might break a design into visual areas for Structure, Menu, Footer, Navigation, Quick Jump Menu, Hero Image etc.

And in this case, our selectors look like this:

.st-Header {
    /* Structural container for header
}

.st-Footer {
    /* Structural container for footer */
}

However, we might just as easily do this:

.hd-Outer {
    /* Structural container for header
}

.ft-Outer {
    /* Structural container for footer */
}

Or even like this if it's the module:

.hd-Header {
    /* Structural container for the Header module */
}

.ft-Footer {
    /* Structural container for the footer module */
}

None of those is wrong or right. As long as child nodes/selectors follow the same naming convention, the styles will be isolated to the particular area.

The reality is that on smaller sites, you could use pretty much any class-naming approach you like and the dangers of collision would be minimal. However, as soon as projects start to grow the benefits of namespacing and a strict naming convention will start to pay you back handsomely.

Organising Modules, their Components and naming files

At this point, I think it will be useful to consider a more detailed example module structure. It's similar to the structure in which I'm used to employing ECSS. It's a little more involved than our prior examples and gives another subtly different variation on how files could be organised and selectors named. As ever, from our CSS point of view our aim is isolation, consistency and solid developer ergonomics. Let's take a look.

Suppose we have a module. Its job is to load the sidebar area of our site. The directory structure might initially look like this:

SidebarModule/ => everything SidebarModule related lives in here
  /assets => any assets (images etc) for the module
  /css => all CSS files
  /min => minified CSS/JS files
  /components => all component logic for the module in here
  css-namespaces.json => a file to define all namespaces
  SidebarModule.js => logic for the module
  config.json => config for the module

In terms of the example markup structure this Module should produce, we would expect something like this initially:

<div class="sb-SidebarModule">

</div>

The CSS that styles this initial element should live inside the css folder like this:

SidebarModule/
  /assets
  /css
    /components
    SidebarModule.css
  /min
  /components
  css-namespaces.json
  SidebarModule.js
  config.json

Now, suppose we have a component inside the SidebarModule that creates a header for the SidebarModule. We might name the component with a file called Header.js and store it inside the components sub-folder of our SidebarModule like this:

SidebarModule/
  /assets
  /css
    /components
    SidebarModule.css
  /min
  /components
    Header.js
  css-namespaces.json
  SidebarConfig.js
  SidebarModule.js
  config.json

With that in place, the Header.js might render markup like this:

<div class="sb-SidebarModule">
    <div class="sb-Header">
        <div class="sb-Header_Logo"></div>
    </div>
</div>

Note how the Header component, due to being within the context of the SidebarModule carries the sb- micro-namespace to designate its parentage. And the nodes created by this new component are named according to the logic that creates them.

In terms of the general conventions to follow:

Components should carry the micro-namespace of the originating logic. If you are creating a component that sits within a module, it should carry a/the namespace of the originating module (possible namespaces for a module are defined in css-namespaces.json).

HTML classes/CSS selectors should be named according to the file name/components that generated them. For example, if we created another component inside our module called 'HeaderLink.js' which renders its markup inside a child of the Header.js component, then the markup it generates and the applicable CSS selectors should match this file name.

For example:

<div class="sb-SidebarModule">
    <div class="sb-HeaderPod">
        <div class="sb-HeaderPod_Logo"></div>
    </div>
    <div class="sb-HeaderPod_Nav">
        <div class="sb-HeaderLink">Node Value</div>
        <div class="sb-HeaderLink">Node Value</div>
        <div class="sb-HeaderLink">Node Value</div>
        <div class="sb-HeaderLink">Node Value</div>
    </div>
</div>

In terms of the folder structure, it would now look like this:

SidebarModule/
  /assets
  /css
    /components
      Header.css
      HeaderLink.css
    SidebarModule.css
  /min
  /components
    Header.js
    HeaderLink.js
  css-namespaces.json
  SidebarConfig.js
  SidebarModule.js
  tsconfig.json

Notice how there is a 1:1 correlation between component logic (the .js file) and the associated styles (the.css files) – both sit within a components sub-folder. Although both logic and styles don't share the same immediate parent folder, they both live within the same module folder, making removal of the entire module simple if needed.

Nodes within a component

To recap. Used in this way, the ECSS naming convention of nodes within a component should always be:

ns-Component_Node-variant

Variants

Note that the -variant part of a node within a component is optional and should only be used to denote subtle variations on otherwise identical items. For example, multiple headers that are identical apart from a differing background image might be rendered like this:

<div class="sb-Classification_Header sb-Classification_Header-2"></div>

Working with generated content from a CMS

It's probable that if you use ECSS with any sort of Content Management System (Wordpress, Ghost, Drupal et al) you will encounter a situation where it's not possible to add a class to every element. For example, in a Wordpress page or post, it would be unrealistic to expect users entering content to remember the right class to add to each paragraph tag. In these situations, I think pragmatism has to win out.

Set a ECSS class to the enclosing element and (grudgingly) accept that all the nested elements will be set with a type selector. Here's some example markup:

<main class="st-Main">
    <h1>How to survive in South Central?</h1>
    <p>A place where bustin' a cap is fundamental. </p>
    <ul>
        <li>Rule number one: get yourself a gun. A nine in yo' ass'll be fine</li>
        <li>Rule number two: don't trust nobody.</li>
    </ul>    

</main>

Here is how you might author the CSS to handle selecting those elements:

.st-Main {
    h1 {
        /* Styles for h1 */
    }
    p {
        /* Styles for p */
    }
    ul {
        /* Styles for ul */
    }
    li {
        /* Styles for li */
    }
}

I'm not crazy about that. We're nesting selectors, tying our styles to elements, basically everything we normally want to avoid with ECSS. However, I'm being honest. The reality is that this is likely going to be the best compromise we can manage. Where it is possible to add a class to elements we absolutely should. However, there will be situations where this simply isn't possible and no amount of Ivory Tower idealism will help in those situations. Remember 'Pin Cing Do'!

ECSS and global styles

Whilst the Lion’s share of CSS in a web application can be described as module based, there is an inevitable amount of global CSS we need to deal with. From an ECSS perspective we should keep this global CSS as minimal as possible. Typically, besides any requisite ‘reset’ styles, there will be a default font-size, font-family and perhaps some default colours. These are styles that are usually applied to type selectors. Unless you have classes on the root HTML element of body for example.

There may also be some global structure needed. For example, if you have a common structure throughout your application (header, footer, sidebar etc), you may want to create some selectors to reflect this. In the past I have used a .st- or .sw- micro-namespace to define ‘Structure’ or ‘Site Wide’ but you can use whatever is most apt for you. However, my advice would be that there really shouldn’t be many of these selectors as these typically relate to very broad areas that all the modules of an application should live within.

In terms of organising global CSS I currently favour a folder in the root of any project called ‘globalCSS’. In that folder would be any variables, mixins, global image assets, any font or icon-font files, a basic CSS reset file and any global CSS needed.

Summary

We've looked at the two principal ways you might apply ECSS in this chapter. We've also considered a possible folder structure for a complete module. I'm hopeful that by this point, you'll have a fair idea of how you might apply ECSS in your projects.

Hand-in-hand with the architectural approach of implementing CSS is the practice of actually authoring your style sheets. You know, how the code actually looks in the editor.

How you should best author style sheets to put all this ECSS malarkey into practice is what we will look at in the next chapter.