Jump to content
Slate Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate Marble
Slate Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate Marble
Sign in to follow this  
Rss Bot

A web designer's guide to CSS methodologies

Recommended Posts


A CSS methodology is a set of guidelines for writing modular, reusable and scalable code. Although CSS is an easy language to write, without an agreed-upon convention the code gets messy almost as fast as it is written. Since each CSS declaration is defined on its own line, files get huge quickly, making them a nightmare to maintain.

To solve this and other CSS implementation issues (for a further explanation, jump to Why do we need CSS methodologies?), groups of coders around the world have developed different CSS methodologies, or sets of standard practices. Each comes with its own focus, advantages and disadvantages. 

They are not frameworks or libraries, rather rules for writing CSS code that encourage developers to stick to conventions that make code easier to write and maintain, saving hours of development time. These methodologies are not mutually exclusive and can be used together in a way that best suits developers. 

In this article we will take a look at the pros and cons of a few of the most popular CSS methodologies: object-oriented CSS, Atomic CSS (related to atomic design), BEM and SMACSS. Use the boxout opposite to jump to a particular methodology. Alternatively, hop to page 2 to see how they can be combined together in a custom methodology.

Object-Oriented CSS

  • In a nutshell: Divide layout into objects, then abstract their CSS into modules

OOCSS involves identifying objects on a page and separating their structural and visual CSS styles into two declaration blocks. These blocks can then be reused by different elements, and changes need only be made in one place, leading to better consistency.

Declaration blocks are applied to elements using single-class selectors to avoid specificity issues. This technique also separates content from container, so objects look the same wherever they appear. Classes also decouple mark-up from CSS. Using .title instead of h2 for heading <h2 class="title"> allows it to be changed to <h3 class="title"> without changing the CSS. 

To further separate HTML and CSS, class names should not include property values. A class 'blue' would require renaming in HTML and CSS if the colour changed.

Using OOCSS a button's CSS and markup can be defined as:

OOCSS introduces many useful concepts, but its lack of rules leads to variations in interpretation that can result in inconsistencies. It has, however, been used as inspiration for stricter methodologies.

Atomic CSS

  • In a nutshell: Create a class selector for every repeating CSS declaration

ACSS encourages developers to define single-purpose class selectors for every reusable declaration. Unlike OOCSS, which discourages CSS property values in class names, ACSS welcomes it. Using ACSS styles can be defined and applied to elements as:

There are programmatic approaches to ACSS that automatically generate CSS based on classes or attributes that users add to the HTML. Atomizer is one such tool, allowing the previous HTML to be redefined as:

This would automatically generate the following CSS upon build:

The main benefit of ACSS is the ease of maintaining consistent code and not having to invent classes for components requiring a single CSS rule. 

However, ACSS used on its own can lead to an unmanageable number of classes and bloated HTML files. It is therefore   common to only use ACSS principles to create helper classes that define consistent, reusable declaration blocks.

Block Element Modifier

  • In a nutshell: Use a standard naming convention for classes

BEM encourages developers to divide layouts into blocks and nested elements. Variations from the average appearance of a block or element should also be identified and applied using modifiers.

CSS declarations are applied using a single class name of format block-name for blocks and block-name__element-name for elements, with two underscores in between. Modifier names are appended to classes, prefixed with an underscore or two hyphens for better clarity, for example block-name__element-name_modifer-name or block-name__element-name--modifer-name. An object is a block if it can exist without ancestors, otherwise it's an element. 

Blocks can have nested blocks and elements, but elements cannot. Modifiers must be used alongside block and element classes, not instead of them.

BEM can be applied to a list, where list-block--inline and list-block__item--active display lists horizontally and highlight items respectively:

BEM is a highly effective naming convention that creates predictably behaving CSS that is easy to manage, maintain and scale. BEM does have downsides, however, including the difficulty in inventing class names for deeply nested objects, the ridiculously long class names and bloated HTML that may sometimes result, and also the lack of consistency that is caused by the inability to share CSS between objects.

Scalable and Modular Architecture for CSS

  • In a nutshell: Split CSS code across multiple files for better performance and organisation

SMACSS works by dividing CSS into five categories – base, layout, module, state and theme – commonly split into separate files. Base styles override the default styles and are mainly applied using element selectors:

Layout styles are for major objects like headers and sidebars. They are applied using IDs or classes with generic helper declarations optionally prefixed with l-:

Module styles are for smaller, reusable objects like buttons and lists, each commonly with its own file. They are applied using classes, with nested items classes commonly prefixed with the ancestor class:

State styles are for changeable states, like hidden or disabled. They are commonly applied with class names prefixed with is- or has- and chained to other selectors:

Theme styles are optionally used for changing the visual scheme. SMACSS provides well-organised CSS code split logically across multiple files. Using SMACSS does, however, introduce specificity traps by allowing IDs and relying on selector chaining for state and some layout declarations.

Next page: Learn how to combine different methodologies to create your own

As you have probably gathered from this article, each CSS methodology comes with its own benefits and drawbacks. It is, however, possible to combine aspects of multiple methodologies together to create your own custom one that's specifically suited to your needs. 

Let's look at one way of combining the four methodologies discussed on page 1, for a site with a homepage and a button component, using Sass as a preprocessor. Applying SMACSS principles, we can divide our code across multiple Sass partials as shown in the image below.

ZHKJwiCVTEF6DdmytbC794.jpg

Click the icon in the top right to enlarge

Then import them into styles.scss that will be converted to styles.css by Sass, as follows:

Next we can add any styles that override the browser defaults to _base.scss, allowing mainly element selectors and their pseudo-classes:

Selector chains are sometimes required to override unwanted styles applied by external frameworks. For example, the Materialize.css framework applies padding to grid columns using a two-class selector chain .row .col, making it impossible to override with a single-class BEM selector. 

Such overrides should also be added to _base.scss, for example .row .col {padding: 16px}. For this to work make sure external libraries are sourced in the HTML before styles.css.

Using ACSS ideas we can create helper classes that apply consistent styles to any element, eliminating the need to create a new class name and component file for elements requiring a single CSS declaration. Instead we can apply the helper class directly to the HTML. For example, we can create a responsive, top margin helper class in _helpers.scss:

For each component we will have a separate file in the components directory and use a BEM methdology. We will allow BEM formatted single-class selectors, their pseudo-elements and an infinite number of chained pseudo-classes. 

For example, the CSS of buttons can be defined in _button.scss as following, with modifier button--is-disabled greying out the button and showing a tooltip with the message disabled on hover:

Finally, we can add page-specific overrides to a corresponding file in the pages directory. To ensure that these overrides are always applied to our elements and those from external libraries with potentially multi-class selectors, we will give each page a unique ID. 

For example, we can hide disabled buttons on the homepage by adding the following to _home.scss:

As you can see, combining methodologies is easy and can lead to a personalised, consistent approach to CSS development that scales effortlessly and is easily maintained. The custom methodology detailed above is just a suggestion, and my advice is for you to develop your own. 

Combine aspects you like from as many methodologies as you can find, adapting them to your liking, and stick to them. There is little point in creating a methodology if you constantly deviate from it. If you find yourself doing so, then incorporate these deviations into your methodology in a way that is consistent and easy to understand.

Why do we need CSS methodologies?

CSS preprocessors such as Sass, Less and Compass, have done wonders to mitigate this problem by allowing selectors to be nested and blocks of code to be replaced with single-line 'mixin' declarations (take a look at What is Sass? for more on this). While this helps, large projects can still require thousands of lines of code. Fortunately, preprocessors also allow CSS to be split across smaller files, or 'partials'. But what to include in each partial and how they are named must be agreed upon by a team, otherwise their use can do more harm than good.

Another potential problem experienced with complex projects is managing specificity. CSS assigns a weight to each style rule, so when multiple rules are used on the same element, the highest weighted rule is considered more specific and is therefore applied. When multiple, equal-weight rules are used the lowest one wins. 

Specificity is calculated using four number groups represented as 0-0-0-0, where numbers do not overflow from one group to another, so 0-12-21-5 is valid. Each element or pseudo-element in a selector increments the right-most group, e.g. h1 is 0-0-0-1 and div::before is 0-0-0-2. Each class, attribute or pseudo-class increments the next group, e.g. .some-class.another-class is 0-0-2-0 and section.some-class .another-class:hover is 0-0-3-1

IDs increment the next group, e.g. #some-id#another-id is 0-2-0-0 and ul#some-id img.some-class:active is 0-1-2-2. Inline styles applied using HTML style attributes increment the leftmost group and are therefore the most specific selectors. 

The higher the overall number, the more specific the selector. So if one developer uses div.some-class to apply styles to an element, it is not possible to override them lower down the code using .some-class on its own. It is therefore common practice to use only single-class selectors when possible.

This article was originally published in creative web design magazine Web Designer. Buy issue 282 or subscribe.

Read more:

View the full article

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×