My Current CSS and Sass Styleguide

It’s never easy to find a way to write consistent, future-proof, and robust CSS. It’s taken me months, if not years, to come up with a clean way to write mine. In fact, my process is still evolving, and I expect it to change even more.

In the meantime I have accumulated enough knowledge to write an article about how I feel about writing CSS. I don’t claim that these suggestions are for everyone, and they’re certainly not perfect. But I thought it would be nice to put these into an article to share them with the community.

Naming conventions

Naming conventions are a team decision. If, like me, you are dealing with your CSS on your own, you can go nuts and use something that suits you. Personally, I go with Nicolas Gallagher’s methodology which is influenced by the well-known Yandex BEM system.

BEM stands for Block Element Modifier, a clever and clean way to name your CSS classes. Yes, I said classes, not IDs. I don’t use any IDs in my CSS and neither should you. Any. IDs are overkill and can lead to specificity issues. Of course, IDs are still very useful for JavaScript hooks and HTML anchors.

The point behind the BEM syntax is to provide context directly into the selector in order to make them easily understandable to anyone new to the project.

Here is a very basic example of BEM:

.block { }
.block--modifier { }
.block__element { }
.block__element--modifier { }

Yes, double dashes, double underscores. We’ll see why in a moment.

So, what’s up with BEM? It looks long and ugly. Well yes it is! But the fact that is is long and ugly is actually what makes it efficient.

The main idea is simple: when you build a component, you give it a name. A child element of the component will be named like this .{{ name of component }}__{{ name of child-element }}. When an element is slightly modified it will be named .{{ name of component }}--{{ name of modifier }}. Of course, a child-element can be modified as well.

So what’s up with the double dashes and underscores? Well, these allow hyphenated names like .my-component. Then you can read .my-component--disabled without a problem. Same goes for the double underscores. Worry not, you will get used to it very quickly.

Since nothing’s better than a good ol’ example, here is a step-wizard module I wrote at work using the BEM naming system (which you can find on CodePen):

.steps { }
.steps__item { }
.steps__item--first { }
.steps__item--last { }
.steps__item--active { }
.steps__item--done { }
.steps__link { }

As you can see, we deal with 3 different elements:

  • .steps which is the module wrapper
  • .steps__item which is the main element for the module since it has at least 4 modified states
  • .steps__link, another element in the module

This may look kind of verbose but I can assure you this is a real pleasure to deal with once you get used to it. It is very descriptive and less prone to mistakes and confusions.

Naming variables

There has been a whole debate over naming Sass variables, especially those involving colors. Should we name our variables like the colors they refer to or should we name them according to their purpose across the project? Basically, which one would you rather have to deal with?

$blue: #4183c4;
// Or
$primary-color: #4183c4;

This is really a matter of opinion. I go with both.

$blue: #4183c4;
$primary-color: $blue;

This way I can have a bunch of cool variables like $blue-like-the-sky, $red-like-blood, and $sexy-pink that make more sense than hexadecimal colors and meaningful variables across the project to determine which color is supposed to be used where (primary here, secondary there, and so on).

Note: Hyphens (-) and underscores (_) are treated the same way in Sass so $blue-like-the-sky and $blue_like_the_sky are both refering to the same variable.

Naming Breakpoints

If you are not already naming your media queries, you really should do so. It makes a huge difference when having to update a breakpoint or read some code that is highly dependent on screen resolution. Naming breakpoints is as easy as using this simple mixin:

@mixin breakpoint($name) {
  @if $name == "small" {
    @media (max-width: 767px) {
      @content;
    }
  }
  @else if $name == "medium" {
    @media (max-width: 1024px) {
      @content;
    }
  }
  @else if $name == "large" {
    @media (min-width: 1025px) {
      @content;
    }
  }
}

I used to pick a simple naming system like: small, medium, and large with the ability to add tiny or huge if required. This has the major benefit of being both very simple to read and device-agnostic, which is not the case with something like phone, tablet, and desktop, which don’t make much sense anymore since we have extra large phones and tablets and very small computer screens.

But! You could think of something more playful if you want to have some fun and your team is okay with it. I still go with baby-bear, mama-bear, and papa-bear from Chris Coyier on my own site, but why not something like r2d2, c3p0 and chewbacca? More cool examples like those are found in Chris’s article.

Tabs vs. Spaces

This is the kind of topic that leads to nuclear war, so I will just give you my opinion of the situation – feel free to think otherwise. I used to use only tabs but I ended up switching to spaces. Two spaces.

I am not sure there are many reasons for this, except that I feel like it suits me best. It has its pros and cons. Among the pros, it avoids having lines starting in the middle of the screen due to extra nesting.

Also, basic editors do not handle tabs very well. Think of textarea elements for instance. They let you insert spaces, but not tabs (unless you copy and paste from elsewhere, which is not ideal). Spaces are supported everywhere. Hence my choice for the former.

CSS Rule Sets

I like when things are clean. All my CSS rule sets are written the same way and they follow strict (yet standard) conventions. Here is an example:

.selector,
.other-selector {
  color: black;
  padding: .5em;
  font-size: 1.2em;
}

Well, this is nothing more than the basics, which includes:

  • One selector per line
  • One space before the opening curly brace
  • A line break after the opening curly brace
  • A consistent indent
  • No space before the colon
  • A space after the colon
  • No space before the semi-colon
  • A line break after the semi-colon
  • No space before the closing curly brace
  • A line break and an empty line after the closing curly brace

Some side notes:

  • I tend to get rid of the padding 0 when dealing with decimal numbers between 0 and 1, making the number start with a .;
  • I try to make colors as short as possible, following this order: keyword > small hex triplet > hex triplet > rgb/hsl > rgba/hsla,
  • I avoid magic numbers at all cost (numbers that are not round or do not make sense by themselves),
  • I don’t use any px values (only em or even rem if browser support allows it) except when it is one (1px); pixels are not scalable, that simply sucks.

Sass Stuff

What I’ve just run through are pretty standard CSS guidelines. Now for some Sass-specific stuff.

.element {
  $scoped-variable: whatever;
  @extend .other-element;
  @include mixin($argument);
  property: value;

  &:pseudo {
    /* styles here */
  }

  .nested {
    /* styles here */
  }

  @include breakpoint($size) {
    /* styles here */
  }
}

The different items in a Sass rule set go in the following order:

  1. Scoped variables
  2. Selector extensions with @extend
  3. Mixin inclusions with @include with the exception of media-query stuff
  4. Regular property: value pairs
  5. Pseudo-class/element nesting with & after an empty line
  6. Regular selector nesting after an empty line
  7. Media query stuff (with or without a mixin)

Taking our step-wizard example from earlier, here is what a real-life example in the above order would look like:

.step__item {
  counter-increment: steps; /* 1 */
  background: $step-background-color;
  float: left;
  padding: $step-baseline 0;
  position: relative;
  border-top: $step-border;
  border-bottom: $step-border;
  white-space: nowrap;
 
  &:after {
    @include size($step-arrow-size);
    @include absolute(top .3em left 100%);
    @include transform(rotate(45deg));
    content: '';
    z-index: 2;
    background: inherit; 
    border-right: $step-border;
    border-top: $step-border;
    margin-left: -$step-arrow-size/2;
  }

  &[disabled] {
    cursor: not-allowed;
  }

  @media (max-width: 767px) {
    width: 100% !important;
    border-left: $step-border;
    border-right: $step-border;
    padding: $step-baseline*2 0;

    &:after {
      content: none;
    }
  }
}

Nesting in Sass

Nesting has to be one of the most controversial features of Sass, or any other CSS preprocessor for that matter. Nesting is both useful – to avoid repeating the same selector again and again – and dangerous, because it can produce unexpected CSS. Only use nesting when it’s what you mean, not just because it is convenient. If you mean, .a .b, then you can write .a { .b { } }. If .b happens to be inside of .a but is enough by itself, don’t nest it.

Inception meme: We need to go deeper

I bet you’ve seen the movie Inception. Great movie, right? Well, you know how the characters can’t go any deeper than a dream within a dream within a dream, otherwise they end up in ‘limbo’? Well Sass nesting is the same: Don’t nest deeper than 3 levels. Ever. If you have to, it means either your markup or your CSS is poorly written. Either way, you might end up in ‘limbo’ and, as we saw in the movie, it ain’t pretty down there.

“Don’t nest deeper than 3 levels.”
Cobb

Comments

When you work with Sass, you have two different ways to write your comments: the good ol’ /* */ you all know well, and the single line comment // that doesn’t exist in plain CSS (although you can get around that). The difference between these is that the single-line comments will not be compiled in the resulting stylesheet, ever. This is why single-line comments are referred to as “transparent comments” or “invisible comments”. Meanwhile, the regular CSS comments will be in the compiled CSS if you’re not compiling in compressed mode (you should be though).

As far as I am concerned, I comment a lot. CSS is a language full of tricks, hacks and dirty little secrets. I feel like I need to comment if I want someone (even me) to understand the code months later, even things that seem obvious at the time of writing the code.

/**
 * Purpose of the selector or the rule set
 * 1. Hardware acceleration hack (http://davidwalsh.name/translate3d)
 * 2. Fallback for unsupported rgba
 */
.selector {
  @include transform(translate3d(0, 0, 0)); /* 1 */
  background: black; /* 2 */
  background: rgba(0, 0, 0, .5);
}

I start with a small description of the rule set, then I number tiny details that are worth an explation. The numbers are then matched with numbered comments at the end of CSS rules (e.g. /* 1 */).

In the end I don’t use single-line comments much, expect in Compass extensions (e.g. SassyJSON). I started doing so when I realized regular CSS comments from my first Compass extension SassyLists were dumped to the CSS output on Sassmeister.

Quasi-qualified selectors with comments

I believe the idea of using comments to avoid qualifying selectors comes from Harry Roberts.

Qualified selectors are bad for many of the reasons described in Harry’s post. The most important ones being: They are over-specified unnecessarily, they break the cascade, and they are not reusable.

That being said, being able to say “this class should only be applied to this type of element” can be useful. Let’s say at some point you use CSS transforms and create a fallback for unsupported browsers, using Modernizr to detect support. Here is what your code might look like:

.no-csstransforms .selector {
  /* Styles here */
}

Now what if you want to explicitly indicate that the no-csstransforms class is meant to be on the html element and not anywhere else? Doing html.no-csstransforms would make your selector over-qualified and is not a good idea. You could use a regular comment above the rule set to make a note, as we’ve seen in the previous section. Or you could try quasi-qualified selectors:

/*html*/.no-csstransforms .selector {
  /* styles here */
}

There you go: the class is now explicitly meant to be bound to the html element without altering you selector at all or breaking anything. This technique may look very odd at first but you can get used to it pretty quickly.

Final thoughts

As already mentioned, you might not feel comfortable using all these rules. And I don’t expect you to. What’s important is that you and your team are able to read each other’s code and update it easily.

Probably the best thing you can do with this post is take these suggestions and make them your own, adding your own flavour to them to improve your own workflow.

If you have developed your own methods for any of these areas of Sass and CSS, we’d love to hear them in the comments.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.growingwiththeweb.com/ Daniel Imms

    Hey Hugo, have you found doing media queries with a parameter gives much benefit over creating a series of mixins with the size in the title, like @mixin media-small, @mixin media-large, etc. It seems like it would be a little less safe to do it with a string parameter since a typo in the argument would not output the inner CSS.

    • http://hugogiraudel.com/ Hugo Giraudel

      True. However a typo in `@include media-small` wouldn’t have the desired effect either. Although I’ll give you that Sass compiler would crash because the mixin doesn’t exist. I suppose you could add a warning whenever the keyword isn’t recognized, thus you’ll know you’ve made a typo.

  • TomButlerRje

    Honestly, I think it’s rather a pointless exercise being quite so pedantic with CSS at this level. The problem with CSS, at a more general level which leads to these sort of tidiness regimes is that it gets over-engineered (just look at how many lines of CSS exist in the average wordpress site with a couple of plugins). A better tactic to keeping CSS maintainable is to simply have less of it and separate it into files which pull in only the files needed.

    What I don’t understand about your BEM suggestion is that CSS already allows that without needing to invent a special notation for it. I can target all child elements in a component using .component .child or .component .child.modifer to suggest that using an alternative, bespoke, more verbose, syntax makes it easier for other developers to understand is nothing short of wishful thinking and in most cases, palpably false.

    • LouisLazaris

      Hi @TomButlerRje:disqus,

      Thanks for your comment.

      Hugo’s suggestions here are for the purpose of making the code easier to read. He’s mostly talking here about naming conventions and code organization, so that really has nothing to do with extra CSS coming from WordPress plugins… I don’t really know what that has to do with anything in this post….?

      And regarding the BEM methodology… BEM-style CSS makes it absolutely clear what is a ‘block’ and what is a ‘modifier’ without having to do really big nesting of descendants in your stylesheets (which is bad, but that’s another 3 paragraphs in another post!). With the BEM method, you rely on a single class that tells you in its notation whether it’s a block or a modifier. With the method you’re suggesting, yes it could work, but you’d have a much more complicated system in place because every modifier would have 2-3 classes chained together (whereas BEM there would just be one).

      And keep in mind that these techniques mean much more in a really large project and while working on a large team.

      • http://r.je Tom Butler

        The wordpress example was purely a good demonstration of how CSS is often completely over-engineered. The only time you really need this level of complexity in CSS is when the CSS is over-engineered. Otherwise, it’s simple enough that there’s no need for such efforts and the time lost in organisation becomes more than it saves.

        I disagree, there are a hundred other ways of doing the same thing that isn’t nearly as verbose as the BEM method. As for 2-3 classes chained together, how is that any different that 2-3 parts separated by dashes and underscores instead of spaces?

        How is .steps__item–done any clearer than .steps .item.done? Generally speaking the modifier will be an adjective and the item/block will be a noun so English achieves this for us without needing a special notation and means that my HTML is tidier because I just have <span class=”item modifer”> instead of the more verbose and ugly <span class=”block__item–modifier”>.

        And then we get onto reusability and consistency. If you use the same modifier, let’s say “disabled” across multiple components, I can say “any disabled element has a strikethrough” using .disabled {} to target all disabled elements and can override using more specific CSS if needed for specific blocks. However, using the block__item–disabled method I need to specify this for every kind of disabled element.

        • LouisLazaris

          > As for 2-3 classes chained together, how is that any different that 2-3 parts separated by dashes and underscores instead of spaces?

          If it’s not different, then why do you have a problem with it? But the fact is, it’s very different. First of all, if you have 3 classes chained, that means you’ll have three different classes in your HTML, as opposed to just one. Secondly, what are the different classes defining? If they’re just for descendants, then you might as well just use hyphens. There’s no reason to use the method you’re describing and contrary to what you’re explaining, your method actually litters the HTML even more. This will also be confusing to future maintainers because they won’t understand why there are 3 classes on an element when only the last class actually has any styles attached to it.

          Also, your barking up the wrong tree here when it comes to BEM… Hugo didn’t invent it! He’s just saying he likes it! :) I think you should talk to the Yandex guys. :)

        • http://ericyoungberg.me Eric Youngberg

          If you are worried about consistency, that’s a major part of CSS Preprocessing…

          .disabled {
          // your code
          }

          .block__item–disabled {
          @extend .disabled;
          // block item specific disabled
          }

          The point is that just using a lot of nested .disabled classes for specific elements instead of having their own tag is not as semantic. That’s what markup is all about. It isn’t “over-engineered.”

    • cmegown

      @TomButler I understand your point but the whole idea behind articles like this is about consistency, readability, and maintainability. While there is obviously some opinion that comes with it, these types of conversations are usually born from experience.

      Consistency is key for writing reusable/modular code in a language that doesn’t truly allow for actual object-oriented programming. The naming conventions and structure introduced with BEM syntax helps enforce consistency on projects of all sizes.

      Readability is key for working with teams and/or handing a project off to another developer. Have you ever been working with someone’s code and spent more time trying to make sense of it than actually making changes? I have, and it sucks.

      Maintainability is key because doing the concept work, writing the code, and launching the product is the easy (and fun) part. Long-term maintenance work can be tedious and extremely difficult if things aren’t set up in a way to allow simple additions and/or changes. When you’re working with small projects, it’s not as big of a deal. If you’re working with larger products, that may be integrated or linked to other products, maintenance becomes one of the most important facets of design.

      TL;DR
      Although code standards like those written in the article may seem over-engineered, they exist because of extensive trial-and-error in projects of all shapes and sizes.

  • http://www.sachagreif.com/ Sacha Greif

    Nice, I do almost exactly the same things.

  • Zeno Zaplaic

    Nice article! It’s worth mentioning that the new Sass 3.3rc3 makes writing BEMs a lot sweeter

    .steps {
    &__item {
    &–first { .. }
    &–last { .. }
    &–active { .. }
    &–done { .. }
    }
    &__link { .. }
    }

    • Thomas Dobber

      I’d be careful with writing your BEM syntax like this. For one, It would make the Inception rule a lot harder to check and you’d actually have to look up the tree to understand which class name you are dealing with. I’ve been thinking about maybe just using this for modifiers.

    • http://hugogiraudel.com/ Hugo Giraudel

      Yes, indeed. In fact, Stuart Robson (the curator of SassNews) wrote a neat little blog post about this: http://alwaystwisted.com/post.php?s=2014-02-27-even-easier-bem-ing-with-sass-33.

      However I can see two downsides to this syntax: for one, as Thomas Dobber said, it makes quite hard to spot what’s going on and how nested you currently are.

      Secondly, this makes impossible to fuzzy-search any selector in a project, which can be a problem. I have still not moved to this syntax at work and I don’t think I will ever do so, even if I like it much.

      That being said, if I decide to use this syntactic sugar, I think I will do it through mixins. I find it very ugly as is, and my Sass syntax highlighter seems to panic with it so far. I like something like this though:

      .module {
      property: value;
      @include element('heading') {
      property: value;
      }
      @include modifier('disabled') {
      property: value;
      }
      }

      Or even `b()`, `e()` and `m()` to be even shorter.

  • Thomas Dobber

    Using mixins for media queries is starting to feel like cheating to me. Don’t get me wrong I’ve been using them and you can use them to do some cool things (like creating separate stylesheets for old IE), but there is a perfectly good syntax for media queries already.

    I agree with everything you mention in your styleguide and my personal taste is exactly the same (to the point, although I really need to start commenting more), but I think it is very important to stay as close to the original syntax as possible the biggest reason for that being that it makes it even easier for fellow web developers to understand.

    I’d suggest using variables in media queries instead. Besides, it is good to keep in mind that: media query breakpoints should not be used much as they should only imply major layout changes and that once we can start using element queries properly we won’t need to name breakpoints because they will be scoped to an element itself.

  • http://scottohara.me/ Scott O’Hara

    I enjoy reading articles like this, it’s always nice to get insight into how my methods compare with others in our field.

    Thanks for sharing.

  • http://hugogiraudel.com/ Hugo Giraudel

    I really think it makes code cleaner, but I can understand why people prefer adding comments at the end of the rule or between two rules rather than before the selector as a whole block.

    I’ve been using this for about 2 years now and I really enjoy commenting this way. I don’t like adding comments between rules, it looks messy to me.

  • http://hugogiraudel.com/ Hugo Giraudel

    I’d say if you’re looking for a naming convention, BEM is probably the easiest choice. It’s easy to use and easy to get used to.

    SMACSS is more like an architecture guide. It’s not just about naming components, it’s also about organizing them, using them and generally speaking keeping a clean and organized project structure.

    Regarding OOCSS now, I don’t like it. I just don’t feel comfortable at all with naming conventions and stuff. It looks messy in my opinion. But again that’s just me.

  • http://hugogiraudel.com/ Hugo Giraudel

    I am not quite sure what to think about Dan’s article. I feel like it doesn’t do much more than adding complexity. It doesn’t solve much in my opinion.

    That being said, I like the idea of class names starting with a dash. They look fun and hacky.

    • Matt Soria

      Yeah, I haven’t tried them out yet, but I could see why they would work, so I might just give ‘em a go.

  • http://hugogiraudel.com/ Hugo Giraudel

    Hey. You should probably update your mixin in order to:
    - avoid looping through the whole map every time, it’s heavy
    - deal with unrecognized breakpoint

    Here is what I suggest:

    @mixin breakpoint($name) {
    @if not index(map-keys($breakpoints), $name) {
    @warn "Invalid breakpoint `#{$name}`.";
    }
    @else {
    @media (min-width: map-get($breakpoints, $name)) {
    @content;
    }
    }
    }

  • manuelwieser

    Nicolas Gallagher uses a slightly different naming conventions now in his SUIT framework which I like more than the one he mentions in the referenced article.

    https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md#components

    The difference is, that he sets block names in pascal case, elements and modifiers in camel case. Just thought I’d share if someone is unsure about all the hyphens and underscores ;)

    ComponentName
    ComponentName–modifierName
    ComponentName-descendantName

    • http://hugogiraudel.com/ Hugo Giraudel

      Ouh, I don’t like. :P

  • http://valentin.radulescu.me/ Valentin Radulescu

    While I agree that BEM has its merits, I still think it’s a messy and ugly way to go about things. Even on a small snippet of code like the step-wizard module example, legibility goes right out the window when you have more than one class per child element.

    I prefer the way SMACSS does modules where you just prefix the block name to child elements (ex: .block and .block-title, .block-text, etc.).

    All this double underscore and double dash business seems like overkill for most projects. One thing good thing about BEM for me is that the name is inherently funny because of this song :) http://youtu.be/5ZrOQDAcMEo

  • Christian

    Great article, please keep us posted on new discoveries.

    The only suggestion I might add is to prefix variable names with a category. For instance with colors I normally name my variables like:

    $color-main, $color-secondary, $color-highlight

    This way I can simply type “$col..” and my IDE will come up with a list of my available colors.

    • http://hugogiraudel.com/ Hugo Giraudel

      Good point, really. :)

  • http://www.12snaps.com/ Paweł Grzybek

    Hugo, you did well! I really enjoy to read about your well organised workflow!

    Only one thing what is still confusing for me is this spaces vs tabs in our CSS. Why everyone recommend to use only 2 spaces? Why not 4 for instance (what is default value in Sublime Text). 4 spaces makes my CSS more readable. We don’t need to nest our code very deep (Inception rule). Why, why why? My work convention is very similar but i still prefer my old good tab (4 spaces).

    • http://hugogiraudel.com/ Hugo Giraudel

      I’m not sure there is any reason other than taste here. I think 2 spaces are enough most of the time. It’s easy to indent, easy to type, no matter the environment, the shortcuts or whatever. I like 2 spaces.

  • francoismassart

    I also like to use CSS Comb to sort the “native” CSS properties.

  • http://hugogiraudel.com/ Hugo Giraudel

    You shouldn’t do `.step { .step__link {} }` but only `.step__link {}`. That’s the whole point of BEM.