July 14, 2013

1. Introduction

It's a very good and important thing to care about flexibility of your styles and their organisation. Why is it so important? Sure, everyone had a project in his practice which had been developing for some time by someone else, maybe by another company. And when such project came to you, you found all styles in a huge single .css file, some of the rules were written inline, other were orginized in blocks, there were no comments, selectors were long and contained several identifiers etc. Your first thought was something like "OMG! Don't wanna see it and don't wanna deal with it!". And this is the first reason to write well-organized flexible styles - not to give a reason to other developers to think and say bad about your code :) But seriously, projects never stop at some point, they are always changing and growing and as a result styles change too. So you have to keep in mind such possible changes when writing your code.

From my view any code should satisfy at least these 3 requirements:

  • Code should be flexible. This means that any change should "cost" low i.e. to make one change you will not have to make a lot of changes in other parts - code should be organized into independent parts, otherwise it will not satisfy this requirement.
  • Code should be easy to read and understand. It becomes more important when other developers are also working with project's styles. And definitely, you should comment your code.
  • Code should be divided into a number of (relatively) small files, and when the project grows, number of these files should grow faster than average number of lines in one file. It's easier and more convenient for me to manage several (maybe a lot of) files than to manage blocks of code in the same file, even if these blocks are independent. And thousands of lines of code in one file really scare me...

2. SMACSS

To achieve 3 points listed above you need to use some particular way of writing your code, use some best practices, use some guidelines, and they should not (noticeably) change from project to project so they should be universal. Because I work with Drupal, I was looking for such way, for such guide in the Drupal's code guides and the answer was SMACCS written by Jonathan Snook. SMACSS describes ways to how to write your CSS code to make it really flexible and extensible. The core of SMACSS is the categorization of CSS rules. SMACSS divides rules into 5 categories:

  1. Base
  2. Layout
  3. Module
  4. State
  5. Theme

Base

Styles in this category are default styles, in most cases they are applied by a single element selector, but may also include attribute selectors, pseudo-class selectors, child selectors and sibling selectors. Base rules do not include class or ID selectors. CSS Resets are also in this category

html,
body {
  background: #fff;
}
input[type=text] {
  font-style: italic;
}
a {
  color: blue;
}
a:hover {
  text-decoration: underline
}
p > span {
  /* Some CSS properties */
}
span + span {
  /* Some CSS properties */
}

Layout

Layout rules are applied to major page components such as header, footer, sidebars etc. - these are regions in Drupal terms. Layout is the only category where ID selectors are allowed and furthermore are actually recommended. But if you use some grid framework, class selectors will probably be used instead. Layout rules use single selector

#header,
#footer {
  /* Some CSS properties */
}
#sidebar-first,
#sidebar-second {
  /* Some CSS properties */
}
#content {
  /* Some CSS properties */
}

There may be a need to react on some context and change styles of layout elements - in this case contextual selector may be used, for example, class applied to some parent element (usually body)

.l-fixed #sidebar-first {
  width: 200px;
}
.l-fluid #sidebar-first {
  width: 20%;
}

- in this example prefix l is used for the layout-related styles to highlight this category relation. So prefixes are commonly used in the SMACSS to highlight relation of styles to some category.

Module

Modules are minor components of the page. So, almost everything you have on the page are modules: navigation, carousel, different widgets etc. Modules are contained by layout elements and also may be contained by other modules. Modules are supposed to be designed as standalone elements, independently on elements by which they are contained, so they may be moved from one part of the page to another without breaking of styles or layout - this gives a flexibility. Use selectors classes to target the module when defining style rules for it. A class should reflect the name of the module (like navigation, search), ID's or element selectors are not allowed. In module category classes do not have category-related prefixes, other categories usually use prefixes. Modules in most cases contain some elements

.menu {
  /* Some CSS properties */
}
.menu > h2 {
  /* Some CSS properties */
}
.menu li {
  /* Some CSS properties */
}

In this example child selector is used for h2 to target element explicitly enough (we want styles of a menu heading only) because there may be other h2 placed inside other elements. Because of the same reasons .menu li selector is not good, and to avoid such kind of problems it is highly recommended not to use element selectors but to use classes.

.menu {
  /* Some CSS properties */
}
.menu-header {
  /* Some CSS properties */
}
.menu-item {
  /* Some CSS properties */
}

In this example we target only to the elements we need to apply styles to. In the previous example you might notice that elements inside the module are prefixed by module name. Jonathan Snook recommends to use such prefixes, because on the one hand from the class you can see which module the element is related to, and on the other hand the use of single selector targets the necessary element and makes sure you will not affect any other elements. Single selectors are good for performance. But from my point of view you may lose readability in this case - you'll not always be able to use short and single-word names like menu or header for modules and module elements, so you'll have to use not only hyphens, but also underscores or double hyphens or double underscores or camelCase or all of these at the same time in class names to distinguish what part is related to the module name and what part is related to the element name. I usually prefer to use 2 or max 3 element selectors to target necessary elements and provide more readability in the code - in most cases you will not win much performance by using single element selectors so there should be balance between readability and performance and you should decide in each particular case what is more significant for you and what way to use.

.menu .header {
  /* Some CSS properties */
}
.menu .item {
  /* Some CSS properties */
}

But you definitely should not write something like this:

.menu .items .item .link {
  /* Some CSS properties */
}

Submodules

Sometimes it may be necessary to change styling of the module depending on some context, for example depending on the section in which module is placed. The 1st thought will probably be to depend on some parent element - but this is not the best way, you should create a submodule instead i.e. apply some additional class to the module element

.menu {
  border: 1px solid #ccc;
}
.menu-item {
  padding: 5px;
}
.menu-horizontal .menu-item {
  display:inline-block;
}

or

.menu {
  border: 1px solid #ccc;
}
.menu .item {
  padding: 5px;
}
.menu.menu-horizontal .item {
  display:inline-block;
}

State

States reflect some dynamic changes of the element on the page, particular state overrides other styles in this case. State changes usually happen via Javascript so stages change on the client side when user looks at and interacts with the page - and this is the main difference with submodules which are defined when page is generated on the server side. States are usually applied to layout elements or to modules

#header.is-sticky {
  /* Some CSS properties */
}
.menu.is-collapsed .header {
  /* Some CSS properties */
}

- is prefix is used in this case to highlight state class.

Theme

Sometimes you may need to change the look of the site or some element, for example to change the color schema of the page - in this case you'll use theme category styles. Theme styles usually affect on colors and images and may override any of rules of other categories. This category isn't frequently used actually.

/* menu.css */
.menu {
  border: 1px solid;
}
/* theme.css */
.menu {
  border-color: blue;
}

It is also possible to use special elements on the page for theming purposes

.theme-background {
  background: url(../images/bg.png) left top no-repeat;
}

- theme prefix is used in this case.

Let's figure out some recommendations and conclusions:

  • Use classes in selectors
  • Don't use IDs in selectors. Layout category is exception.
  • Try not to use element selectors. Base category is exception.
  • Do not use overnested selectors
  • Use prefixes in class names

There are also some file organization recommendations:

  • Place all Base rules into a separate file
  • Place all Layout rules or even each layout type into a separate file
  • Place each module rules to a separate file
  • Place global States rules into a separate file.
  • Place all layouts and states related to module, including media queries, into a module file.

Was this article helpful? Click to rate: 
Average: 5 (1 vote)

You may also like

INTRODUCTION A modern website and its design isn’t a simple text node...
Stylus is a quite new but a dynamically developing CSS preprocessor....
Theming is a thing no project can be done without. Though it is not...