Naming classes and selectors with ECSS

Back in Chapter 3, Implementing Received Wisdom, I recognised the benefits that the BEM approach of naming CSS selectors gave us. Naming a block and then naming any child elements in relation to that block created a namespace for the child elements.

Namespacing the CSS of a module creates a form of isolation. By preventing name collisions with other elements, chunks of CSS can be more easily moved from one environment to another (from prototype to production for example). It's also far less likely that a change of styles on one selector would inadvertently affect another.

Note

There are a number of other approaches to solve the name collision problem. For example, if you are building an application with the popular React (https://facebook.github.io/react/) framework, consider Radium (https://github.com/FormidableLabs/radium) which will inline the styles for each node so you can effectively serve no CSS at all. Naturally, there are trade-offs such as a lack of caching and no way to add reset styles but it it certainly solves the issue at hand. In addition, when not building with React, consider CSS Modules (https://github.com/css-modules/css-modules). While requiring more involved tooling than ECSS it means you could forgo having to think about naming things altogether as it creates CSS scoped for you. Read more about that here (https://medium.com/seek-ui-engineering/the-end-of-global-css-90d2a4a06284).

ECSS takes the notion of selector namespacing and turns it up to 11 (https://en.wikipedia.org/wiki/Up_to_eleven). Selectors are effectively namespaced in two ways:

  • A micro namespace: usually used to designate context but can also indicate a parent module
  • The module's own namespace: usually the name of the logic file that created the element in question

Let's look at these in more detail. The micro namespace is a simple 2–3 letter namespace for each module. Building a shopping cart? Try. sc- as your micro namespace. Building the next version of that same shopping cart? That'll be. sc2- then. It's just enough to isolate your component styles and allow the styles to be more self documenting. Let's consider a more involved example.

Tip

When it comes to naming things, different things will make sense in different projects. While ECSS can happily adapt to different approaches, I would recommend a consistent approach on each project.

For example, suppose the micro namespace was being used to convey the parent or origin of the logic that created it. Back to our shopping cart example. We might have a file called ShoppingCart.php that contains all the logic relating to our imaginary shopping cart. We could therefore use sc- as an abbreviation of that file name so we know that any elements that begin with that namespace relate to the shopping cart and are rendered by that related file.

In this case, we would then have selectors like:

  • sc-Title : The title of the shopping cart
  • sc-RemoveBtn : A button that removes an item from the shopping cart

Here the selectors are quite compact-aesthetically pleasing if a selector can even be described in that way. However, suppose we have a shopping cart which can live in multiple contexts. A mini cart view and a full page view. In that instance we might decide to use the micro namespace to convey context. For example:

  • mc-ShoppingCart_Title : The title of the shopping cart, generated by the file ShoppingCart when in the mini cart view/context.
  • mc-ShoppingCart_RemoveBtn : The remove button of the shopping cart, generated by the file ShoppingCart when in the mini cart view/context.

Neither of these is the one true way. Part of ECSS philosophy is that while some core principles are essential, it can adapt to differing needs. Generally speaking, for smaller scale use cases, the former approach is fine. However, despite the comparative verbosity of the selectors in the second approach, it is the most resilient and self-documenting. With the second approach you know context, the file that generated the selector (and therefore the module it belongs to) and the element it relates to.

Note

There is more specific information about applying ECSS conventions to web applications and visual modules in Chapter 7, Applying ECSS to Your Website or Application.

Reiterating the benefits

As namespaced modules and components are almost guaranteed to not leak into one another, it makes it incredibly easy to build out and iterate on new designs. It affords a hitherto un-thinkable blanket of impunity. Just make a new partial file for the thing you are building, assign a suitable micro-namespace and module name and write your styles, confident in the fact you won't be adversely affecting anything you don't want to. If the new thing you are building doesn't work out, you can just delete the partial file, also confident that you won't be removing the styles for something else. CSS authoring and maintenance confidence - finally!

Source order becomes unimportant

As our rules are now isolated, it makes the order of rules in a style sheet unimportant. This benefit becomes essential when working on a large-scale project. In these scenarios it is often preferable for partial files to be assembled in any order. With rules isolated from each other, this is simple. With our self-quarantined rules, it makes file globbing of partial styles sheets simple and risk free. With some basic tooling in place you can compile all the CSS partials within a module in one fell swoop like this:

@import "**/*.css";

No more writing @import statements for every partial in a project and worrying about the order they are in.

Tip

We will talk more about file globbing in Chapter 9, Tooling for an ECSS Approach.

Anatomy of the ECSS naming convention

As the naming of items is so useful and essential to achieving our goals, the following section documents the naming convention of ECSS in more detail. Think of this like a Haynes manual (https://haynes.co.uk/catalog/manuals-online) for your CSS selectors.

Here's a breakdown of an ECSS selector:

.namespace-ModuleOrComponent_ChildNode-variant {}

To illustrate the separate sections, here is the anatomy of that selector with the sections delineated with square brackets:

.[namespace][-ModuleOrComponent][_ChildNode][-variant]

Tip

With more than a couple of developers on a project I'd recommended that commits to a codebase are automatically rejected that don't follow the ECSS naming pattern. Some information on necessary tooling to facilitate this is covered in Chapter 9, Tooling for an ECSS Approach.

Explanation of selector sections

Let's go back over the various parts of the ECSS selector and the allowed character types:

  • Namespace: This is a required part of every selector. The micro-namespace should be all lowercase/train-case. It is typically an abbreviation to denote context or originating logic.
  • Module or Component: This is a upper camel case/pascal case. It should always be preceded by a hyphen character (-).
  • ChildNode: This is an optional section of the selector. It should be upper camel case/pascal case and preceded by an underscore (_).
  • Variant: This is a further optional section of the selector. It should be written all lowercase/train-case.

Using this syntax, each part of a class name can be logically discerned from another. More information on what these sections are and how they should be employed follows:

Namespace

As discussed above, the first part of a HTML class/CSS selector is the micro namespace (all lowercase/train-case). The namespace is used to prevent collisions and provide some soft isolation for easier maintenance of rules.

Module or Component

This is the visual module or piece of logic that created the selector. It should be written in upper camel case. I've seen ECSS applied to great effect when the module or component directly references the name of the file that creates it. For example, a file called CallOuts.js could have a selector such as sw-CallOuts (the sw- micro namespace here used to denote it would be used Site Wide). This removes any ambiguity for future developers as to the origin point of this element.

Child node

If something UpperCamelCase is preceded by an underscore (_) it is a child node of a module or component.

For example:

.sc-Item_Header {}

Here, _Header is indicating that this node is the Header child node of the Item module or component that belongs to the sc namespace (and if it it were a component, that namespace could indicate the parent module).

Variant

If something is all lowercase/train-case and not the first part of a class name it is a variant flag. The variant flag is reserved for eventualities where many variants of a selector need to be referenced. Suppose we have a module that needs to display a different background image depending upon what category number has been assigned to it. We might use the variant indicator like this:

.sc-Item_Header-bg1 {} /* Image for category 1 */.
sc-Item_Header-bg2 {} /* Image for category 2 */.
sc-Item_Header-bg3 {} /* Image for category 3 */

Here the -bg3 part of the selector indicates that this. sc-Item_Header is the category 3 version (and can therefore have an appropriate style assigned).

Doubling up on ECSS selectors

Our previous example indicates a perfect situation where it would be appropriate to use two classes on the element. One to assign default styles and another to set specifics of a variant.

Consider this markup:

<div class="sc-Item_Header sc-Item_Header-bg1">
    <!-- Stuff -->
</div>

Here we would set the universal styles for the element with sc-Item_Header and then the styles specific to the variant with sc-Item_Header-bg1. There's nothing revolutionary about this approach, I'm just documenting it here to make it clear there is nothing in the ECSS approach that precludes this practice.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.24.180