DoCSSa {dok~sa}

Sass based CSS architecture and methodology


About

What is DoCSSa ?

DoCSSa is a CSS architecture and methodology that aims to combine all the good parts of the current state of the art.
It is intended for use in large, long lived sites, on which many frontend developers may be working over time.
The name stands for Deferred Object CSS Architecture.

What are the benefits of doing things the DoCSSa way?

  • DoCSSa lets you define snippets of style you can reuse everywhere, without repeating yourself, while keeping the flexibility you need and correct semantics.
  • DoCSSa is scalable and maintainable. It is based on Sass, and suggests a file structure that allows for small, modular components. As most thing have a dedicated place, the developers can easily find the part they have to work on, update it, remove obsolete rules, etc.
  • DoCSSa keeps your CSS from leaking to unwanted places by using a naming convention for classnames, which reflects the modularity of the reusable blocks at work and their constitutive elements.
  • DoCSSa is easy to setup and as flexible as you want it to be. It's only a starting point. Where you go from it is up to you and your team!

Why does DoCSSa exist ?

As frontend web developers, we are living in a world of evergrowing complexity. What once was a relatively easy thing to do (putting aside browsers inconsistencies) has grown into a very complex, dynamic, everchanging reality.

We can't put up to the pace, and honestly do we really want to? Wouldn't we be better off by planning ahead what can be planned and setting up a flexible structure in order to be more efficient and less under pressure when the rough times come? The way we see it, the more work we can avoid by having defined the right tools and the right architecture ahead of time, the better.

DoCSSa is our attempt at an organization that aims toward a faster workflow without sacrificing the long run flexibility.

How does DoCSSa bring its benefits ?

DoCSSa is based on Sass, and leverages some of its key features to achieve its goal. Most notably, DoCSSa takes advantage of placeholders, mixins, and imports. It also suggests a file system organisation and a BEM based naming convention, and integrates the core ideas found in OOCSS, SmaCSS and DRY CSS.


File Structure

Basics

In DoCSSa, the file system is divided in four main directories in the sass folder :

Each base folder has a specific role, and CSS rules for a particular set of elements will end up in one of these directories, according to their nature.
The structure has a single point of entry, which we'll call custom.scss. This file is located at the root of the sass folder.

In most cases, it will be the only file with no underscore(_) prefix : as you may know, the .scss to .css convertion process in Sass only converts files that don't have an underscore in front of them. Most of the files in our structure being imported by other files, they don't need to be rendered directly.
Only components may be rendered separately, in order to be able to dynamically load them if needed, but we'll get back to it.

The main .scss file will look something like this :

  • // custom.scss
@charset "UTF-8";
/*!
========== INIT
*/
@import 'vendor/_normalize';
/*!
========== BASE
*/
// variables, fonts, mixins, helpers... common styles used across the entire site
@import 'base/__base';
/*!
========== COMPONENTS
*/
// reusable components
@import 'components/__components';
/*!
========== SPECIFICS
*/
// declarations specific to the project, organized according to the items/sections represented
@import 'specifics/__specifics';

As you can see, it mostly acts as an aggregator for other files, which themselves import some other scss files, and so on. With a well thought organization, this construct can prove very powerful.

On a sidenote, remember that Sass is only a CSS precompiler, so you'll end up with only one .css file with all the goodies, not a bunch of HTTP requests!

Here is an overview of what a basic file system might look like :

// file system
sass
¦   custom.scss
¦
+---base
¦   ¦   __base.scss
¦   ¦   _config.scss
¦   ¦
¦   +---project
¦   ¦       __project.scss
¦   ¦       _fonts.scss
¦   ¦       _globals.scss
¦   ¦       _helpers.scss
¦   ¦       _variables.scss
¦   ¦
¦   +---utils
¦           __utils.scss
¦           _helpers.scss
¦           _mixins.scss
¦           _system.scss
¦
+---components
¦   ¦   __components.scss
¦   ¦
¦   +---button
¦   ¦       _button.scss
¦   ¦
¦   +---roundedButton
¦   ¦       _roundedButton.scss
¦   ¦
¦   +---tabs
¦   ¦       _tabs.scss
¦   ¦       tabs.standalone.scss
¦   ¦       tabs.standalone.html
¦   ¦
¦   +---verticalMenu
¦           _verticalMenu.scss
¦
+---specifics
¦   ¦   __specifics.scss
¦   ¦   _main.scss
|   |   _inbox.scss
¦   ¦
¦   +---popins
¦           __popins.scss
¦           _popin-congratulations.scss
¦           _popin-loginForm.scss
¦
+---vendor
    _normalize.scss

Base folder

The "base" folder contains rules that are global to the site. It is divided in two parts :

Both summary files (__project.scss and __utils.scss) for those folders import the base/_config.scss file which contains configuration information required by both the system and the project. If you're wondering why we don't import the config from the __base.scss file, you're asking yourself the right questions! We had to stray a bit from our convention about sass files organization on that one in order to ease the standalone components generation. We assumed it was better to import the file twice in "base" than once in "base" and then once for each component declaration.
As of today, this file contains $baseFontSize which is required for the "remIt" mixin, and $breakpoints which is required for cross-media placeholders.

Utils contains only things that don't need to change from a project to another. As of today, it consists of _system, _helpers, and _mixins.

  • _system is a special file the contains tools used by DoCSSa.
    Most notably, it contains a define mixin used to allow inclusion of placeholders from several places without generating duplicate content, and _add()/_use() mixins for handling cross media placeholders.

    To have a specific component's CSS file rendered, the component's .scss file needs to import the placeholders contained in _helpers.scss. But when generating the whole project's CSS, we don't want that multiple import to screw up the output. define is a simple mixin taking advantage of the @content instruction Sass provides, which allows us in the end to have a clean .css file even though we import our placeholders file several times from various places. Dig in the provided example structure if you want to find out how this works.

    As you'll notice, DoCSSa makes heavy use of placeholders. By default, Sass doesn't like it when you try to use a placeholder defined on the root from within a media query and will throw nasty errors at you for that. Thankfully, some nice folks have found a way around it, and we've implemented it in DoCSSa. More on that in the "Responsive" section.

  • _helpers are Sass placeholders that represent a simple CSS functionnality that can be implemented by many classes. For example, %clearfix can be extended by any class that would need to contain floats.

    Placeholders have been a great addition to Sass. They are the magic that allows us to have an object oriented architecture without polluting the markup. For those not familiar with placeholders, they work a bit like mixins, but instead of placing a set of CSS rules within the selector implementing them, they add that selector to the list of selectors on which to apply a set of CSS rules.
    This may not seem as much, but you'll see some of the awesome stuff we can do with it in the components section.

  • _mixins have quite the same purpose as placeholders, but they do require parameters. Mixins are particularily useful for handling vendor prefixes and fallbacks. For example, DoCSSa comes with a linear-gradient mixin that compiles to all required vendor prefixes (and only those required!) and generates a fallback color from the input values for browsers that don't support linear-gradient at all. DoCSSa recommends using Modernizr for feature detection and progressive enhancement, and the provided mixins implementing CSS3 features rely on it by default for their output, even though it can be disabled at include time.

    Mixins, like placeholders, can accumulate and enrich your library with no cost, as they are only compiled when used.
    Mixins are a great way to avoid repetition when coding, but they end up in code repetition in the css output. That's why we only use them when they have to output something that needs to be configured. For generic code that can be reused as-is, we use placeholder helpers instead.

Project has quite the same role as the utils folder, but it is project oriented while utils is intended to be kept and grow from a project to the next. As of today, it consists of _variables, _fonts, _globals, and _helpers.

  • _variables is were all site wide variables reside. Default values, color theme, configuration variables go into this file.

    Here's what the _variables.scss file might look like :

    // _variables.scss
    /* _____ VARIABLES _____ */
    // Generic
    // ==========================================================================
    $default-borderRadius: 4;
    $containerWidth: 760;
    $left-nav-width: 200;
    $nav-variant: 'base';
    // Colors
    // ==========================================================================
    $color-default-light:       #fff;
    $color-default-dark:        #333;
    $color-default-darker:      #000;
    $color-main:                #449888;
    $color-main-light:          #5cbcaa;
    $color-main-lighter:        #a8d5cd;
    $color-secondary:           #ee746f;
    $color-alt:                 #f1ede4;
    $color-alt-dark:            #c2c0bc;
    $color-alt-light:           #f8f5ec;
    $color-alt2:                #637c84;
    
  • The _fonts file is used —you guessed it— for the font-families declaration.
    In our implementation, we use a font mixin that is in charge of generating a bulletproof syntax according to the passed configuration for each needed font, according to a file naming convention.

    But where do we have to place the font files themselves, you may be wondering? Well, as this Sass structure is intended to be compiled to CSS in a different directory, the fonts will be in that directory. Typically, you'll have the custom.scss file in a "sass" folder" compiled to a custom.css in a "css" or "styles" folder. The font files will have to be there (preferably in a "fonts" subfolder in order to stay nice and tidy).
    Same goes for all the image files you may be referring to in your stylesheets.

  • _globals contains rules that are global to the site. Things like box-sizing type, html font size, body background color, headings and link defaults, etc. are defined here. It is also be a good place to store your layout definition if it is used for all pages on the site.

  • _helpers contains placeholders helper that are specific to your current project. If you have a reusable visual component that wouldn't make sense in another project and can be applied to your selector through a simple @extend, this is where it belongs. For more advanced reusable components, the "components" section is what you're looking for.

Components folder

The "components" folder is where your complex ui-components are located. It plays quite the same role as the _helpers file in the base/project folder, but in a way more evolved way. You can think of it as configurable helpers on steroids.
Components are so important in DoCSSa that we needed a dedicated section to explain all there is to know about them, so we won't say much more about them here.

Specifics folder

The "specifics" folder is your common playground. It is where you'll place the rules that don't belong in the "base" or "components" folders. Until you become fluent with DoCSSa's organization rules, what will eventually end up in a component will probably exist in here first.

Specifics is the closest thing to your usual CSS file, except for it's organization. Everything in there is split and dispatched in files and folders according to what they apply to.

By convention, we're using two underscores(__) as a prefix for files that act (mostly) as an import summary, and only one underscore(_) for files which are content only. This usually evolves with the project: you begin with an underscore prefixed file, you add another one, and at some point you stop calling them directly from the main .scss file and you reorganize them in a folder with a summary file.

DoCSSa encourages you to keep your definitions tidy and reorganize in subfolders as soon as it makes sense.
No file should ever be big enough that you can't scroll through it in a few mousewheel movements max.

Before everyone in your team is familiar with DoCSSa, it can be helpful for occasional contributors wondering where to place their code to have a dedicated file. In such case, we recommend using a _inbox.scss file in the "specifics" folder and ask them to commit their work in there.
It shall be emptied regularly by a more experienced DoCSSa user, who would move the CSS rules defined in there to the correct place in the architecture.

Vendor folder

The vendor folder is where we place CSS files that come from third parties and can be updated at any time. As the .scss syntax is CSS compatible, all we have to do is to rename the .css file to .scss, in order for it to be integrated to the .css compilation instead of referenced by the CSS file as a classic @import.

_normalize.scss is an excellent candidate for this section, along with more project specific third party CSS.


Components

Introduction

Components are an important part of DoCSSa. They are intended to be as reusable and extendable as possible. Ideally, they should be reusable in a totally different project without writing any additionnal code. They are, along with the placeholder helpers, the "Deferred Object" part of DoCCSa, thanks to the power of placeholders and mixins.

We say the Object is Deferred because its core resides in an abstraction (the placeholders) instead of being tied to a classname. DoCSSa's components are class agnostic. They are made of placeholders and mixins. The placeholders define a component, and a component mixin is in charge of binding those placeholders to one or several HTML class(es). Thanks to the BEM naming convention, the class passed to the component mixin can be a prefix for other classes onto which to bind placeholder functionalities.

This allows for components to be instantiated on any class, and to be extendable if needed.

As the component is not tied to a particular class, you can use it on whatever class you want, whenever you want, from the CSS side. That means that you can (and should) keep a semantic meaning to your HTML classes, and change their look and feel without having to modify the markup. When your markup comes from a RTE, this is a huge gain. You can change the styling without asking the contributors to change their habits, and you can affect everything already written without having to make search&replace throughout a database or without having a "red" class helper mean the color is going to be purple!

For example, instead of having a link with the "button red" classes, you can give it a "navTrigger" class and bind a button component with a red skin to it. You could also use the same component on a "submitTrigger" class so that both look the same. When time comes to have a different look for your submits, all you have to do is bind the submitTrigger to another component and you're done, without affecting the navTriggers and without touching the markup.

If you need a component with a slightly different behaviour than the original one, you have two options : you can pass a parameter to the mixin to change the binding (or rules), or you can create a subComponent that will import the component's definition to get access to its placeholders, and make a new mixin that will handle the altered implementation.

For example, your component can bind the %exampleAltState placeholder to #{$selector}:hover by default, but bind it to the #{$selector}_#{$hover} class for special cases.
Here is what it could look like :

// component example
// map the placeholders content to some selectors through a mixin
@mixin example($selector: '.example', $hover: ':hover', $param2: '', $defaultSkin: true) {
  #{$selector} {
    @extend %example;
  }
  #{$selector}_inner {
    @extend %exampleInner;
  }
  @if $hover == ':hover' {
    #{$selector}:hover {
      @extend %exampleAltState;
    }
  } @else {
    #{$selector}_#{$hover} {
      @extend %exampleAltState;
    }
  }
  @if $defaultSkin != false {
    @include example-skin-default($selector, $hover, $param2);
  }
}

In order to fulfill their role, components need to respect those two guidelines :

  • A component should be self contained.

    This means that what is outside of the visual boundaries of the component doesn't belong in the component definition. Typically, things like margins or positioning should reside in the "specifics" folder, not in the component. This is required for your component to live in any possible context.

  • Structure(layout) should be dissociated from skin(paint).

    For example, background color, images, text colors, etc. should go into the skin section of the component, not in its core definition. That way, you can create additional styles for them without altering their expected behaviour as a component, and choose what visual style you want when binding the component to a classname.

Of course, it's up to you to compose with those precepts and adapt them to your constraints, but respecting them results in a clean separation of concerns and genuinely reusable components, which is much likely to make your dev faster further down the road, and that is what DoCSSa is aiming for.

When beginning with DoCSSa, it's easy to think as everything as components, as they are so powerful. You must be careful about that, and think about what needs to be a component and what doesn't.
If you component-ize every set of rules, you risk spending more time building the same thing as you would have in the "specifics" folder without enough additional value for it to be worth it. Try to begin with small components to get the hang of it, and adjust your use little by little.
You can begin everything the way you are used to in the "specifics" folder, organize it in imported files and subfolders the DoCSSa way, and only extract a functionality to a component when you feel that it would help you.
DoCSSa only gives you tools to play with, what you implement and how you do things with it is up to you. That's what we believe a "framework" should be anyway.

Description

When looking at a component folder, you may see three files, and eventually some subfolders. Let's take a Tabs component as an example, as probably everyone has already seen a tabbed navigation in a page. The files in the Tabs folder would be: _tabs.scss, tabs.standalone.scss, and tabs.standalone.html.

The underscore prefixed file (_tabs.scss) is the component definition. It is the only essential file for the component, the others are optional.
Let's look at it in details.

Component's definition

The component definition file contains two sets of placeholders named after the component's name, and two mixins. One set is for the component structure, one for the component's skin. Placeholders are wrapped in a define mixin, so that we can import the component from anywhere without any risk of having our placeholders duplicated in the final css.

Here's the structure part of our "tabs" component :

  • // components/tabs/_tabs.scss
@import 'sass/base/utils/__utils';
// _____ STRUCTURE _____ //
// define component placeholders for component contents (no selector here except for component's id)
@include define('tabs') {
  %tabs {
    list-style: none;
    padding: 0;
    margin: 0;
    font-size: 0;
    display: inline-block;
  }
  %tabs_item{
    @include remIt(font-size, 18);
    padding: 10px 0;
    display: inline-block;
    vertical-align: bottom;
  }
  %tabs_link {
    padding: 0 10px;
  }
}
// map the placeholders content to some selectors through a mixin
@mixin tabs($selector, $defaultSkin: true) {
  #{$selector} {
    @extend %tabs;
  }
  #{$selector}_item {
    @extend %tabs_item;
  }
  #{$selector}_link {
    @extend %tabs_link;
  }
  @if $defaultSkin != false {
    @include tabs-skin-default($selector);
  }
}

Don't worry about the id selector for now, we'll get back to it in the "standalone component" chapter.

First, the component imports 'sass/base/utils/__utils', which will give it access to the default mixins and helpers. Thanks to the define mixin, all components can safely import this folder.

Then, a bunch of placeholders are defined, wrapped in a define mixin so that they can safely be imported by subComponents if needed. They are the core of the component, and define what needs to be implemented on the various classes or states of the component.

Below the defined wrapped placeholders is a mixin named after the component. Its role is to actually bind the components placeholders to the provided classname, its "elements", and its state.

By default, the component binding will also implement the default skin. If we have defined another skin, all we need to do is pass "$defaultSkin: false" when instantiating the component, and call another skin binding mixin to handle the component's skin.

We said earlier that a component folder may have subfolders. One of those is a "_skins" folder that would host different skins that we could import as needed. The other possible folders are subComponents folders, that would extend the component. The "_skins" folder is prefixed by an underscore only so that it always show on top of the list, instead of appearing among the subComponents folders.

Now let's look at the skin part of our "tabs" component :

// A component's skin part
// _____ SKIN _____ //
@import 'sass/base/project/_variables';
@import 'sass/base/project/_helpers';
// define component placeholders for component skin (no selector here)
@include define('tabs-skin-default') {
  %tabs-skin-default__item {
    border-bottom: solid 3px transparent;
  }
  %tabs-skin-default__item_current {
    border-bottom: solid 3px $color-green;
  }
  %tabs-skin-default__item_hover {
    border-bottom: solid 3px $color-green-light;
  }
  %tabs-skin-default__link {
    border-left: solid 1px $color-green;
    text-decoration: none;
    color: $color-green;
  }
  %tabs-skin-default__link_first {
    border-left: inherit;
  }
  %tabs-skin-default__item_hover_link {
    color: $color-green-light;
  }
  %tabs-skin-default__item_current_link {
    color: $color-green-light;
  }
  %tabs-skin-default__item_highlighted {
    color: $color-grey-dark;
  }
}
// provide a default skin for the component
// only visual changes that don't affect the component layout should be in here
@mixin tabs-skin-default($selector) {
  #{$selector}_item {
    @extend %tabs-skin-default__item;
    &._is_current {
      @extend %tabs-skin-default__item_current;
    }
    &:hover {
      @extend %tabs-skin-default__item_hover;
    }
  }
  #{$selector}_link {
    @extend %tabs-skin-default__link;
    #{$selector}_item:first-child & {
      @extend %tabs-skin-default__link_first;
    }
    &:hover {
      @extend %tabs-skin-default__item_hover_link;
    }
    #{$selector}_item#{'--highlighted'} & {
      @extend %tabs-skin-default__item_highlighted;
    }
    #{$selector}_item._is_current & {
      @extend %tabs-skin-default__item_current_link;
    }
  }
}

As you can see, it is very close to the structure part. Actually it is placed inside the component's folder for simplicity, but it could very well reside in a _skins folder right away.

As the "skin" part of the component is usually project related, it makes sense that it imports the _variables and _helpers files. This is only a requirement when generating standalone CSS, as those files would be already imported from the custom.scss file in the context of your project.

We recommend that the "structure" part of the component doesn't make use of any project variable in order to stay as generic and reusable as possible.
Usually that is not a problem, but if for some reason you need to import the project variables anyhow for you component structure, you're just one @import away.

As stated before, a component's "structure" should only contain it's layout, it's skeleton. The "skin" part, unlike the structure, should only contain rules that don't affect the structure. These rules can be background-colors, background-images, border-radius, shadows, opacity... Anything you want as long as it doesn't fiddle with the component's external boundaries.
It is not always easy, but the more you practice it the more it feels natural, and the easier it is to find out the right place when you come back to adjust something about your component.

Implementation

Now that we know how a component is structured, it's time to implement it. This is done by calling the component mixin and passing it a class selector.

Here's what an implementation may look like :

// in specifics/_main.scss
    @include tabs('.mainMenu');
    

That's right, now that you have defined your component, using it is as easy as that!

And here is what the output css will look like :

// in css/custom.css
.mainMenu {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: 0;
  display: inline-block;
}
.mainMenu_item {
  font-size: 18px;
  padding: 10px 0;
  display: inline-block;
  vertical-align: bottom;
}
.cssremunit .mainMenu_item {
  font-size: 1.125rem;
}
.mainMenu_link {
  padding: 0 10px;
}
.mainMenu_item {
  border-bottom: solid 3px transparent;
}
.mainMenu_item._is_current {
  border-bottom: solid 3px #449888;
}
.mainMenu_item:hover {
  border-bottom: solid 3px #5cbcaa;
}
.mainMenu_link {
  border-left: solid 1px #449888;
  text-decoration: none;
  color: #449888;
}
.mainMenu_item:first-child .mainMenu_link {
  border-left: inherit;
}
.mainMenu_link:hover {
  color: #5cbcaa;
}
.mainMenu_item._is_current .mainMenu_link {
  color: #5cbcaa;
}
.mainMenu_item--highlighted .mainMenu_link {
  color: #333333;
}

If later on you need to bind the tabs component to another class, all you have to do is to call the mixin with that class and the parameters you want, and you're done!

For example :

// in specifics/_main.scss
@include tabs('.articleTabs', $defaultSkin: false);
@include tabs-skin-alternate('.articleTabs');

Standalone component

The _tabs.scss file is really the only one needed for your component, as long as it includes a skin for the component. But there are two other files that we presented earlier : tabs.standalone.scss and tabs.standalone.html.
Those are here to provide a version of the component already bound to a classname, and an html template describing what the associated markup should look like.
As the tabs.standalone.scss file isn't prefixed with an underscore, it will get rendered by Sass into a .css file. This can be useful when you want some javascript to dynamically instantiate a component and load its associated CSS, instead of providing the component's CSS along with the main stylesheet.

Here's what the standalone scss file would look like for our tabs example :

// tabs.standalone.scss
@import '_tabs.scss';
#docssaComponent__tabs-dynamicTabs {
  content: 'loaded';
}
@include tabs('.dynamicTabs');

As you can see, we use an id in the standalone version of the component. It is intended for load detection :
when dynamically loading components from javaScript, you should first check if it hasn't already been loaded from some other place, and only load it if required.
We recommend using the component name, separated by a dash from the classname it is bound to, and prefixed by #docssaComponent.
This way you'll know what you're dealing with, and avoid collision with other CSS selectors.

Each component folder should also contain a standalone version and a HTML example, so that fellow developers know what is the expected structure HTML-wise and can test the result easily.
Components need a structure to apply on. If they didn't, a placeholder helper would be enough.
It can be really useful to maintain a project Style Guide, including every component standalone as a reference.

Here's what the html sample file may look like for our tabs example :

// tabs.standalone.html
<ul class="dynamicTabs">
    <li class="dynamicTabs_item">
        <a class="dynamicTabs_link" href="#tabContent1">tabContent1</a>
    </li>
    <li class="dynamicTabs_item">
        <a class="dynamicTabs_link" href="#tabContent2">tabContent2</a>
    </li>
    <li class="dynamicTabs_item">
        <a class="dynamicTabs_link" href="#tabContent3">tabContent3</a>
    </li>
    <li class="dynamicTabs_item">
        <a class="dynamicTabs_link" href="#tabContent4">tabContent4</a>
    </li>
    <li class="dynamicTabs_item">
        <a class="dynamicTabs_link" href="#tabContent5">tabContent5</a>
    </li>
    <li class="dynamicTabs_item">
        <a class="dynamicTabs_link" href="#tabContent6">tabContent6</a>
    </li>
</ul>

Naming conventions

HTML classes

In DoCSSa, we decided to follow BEM class naming convention.
HTML class names for Blocks are lowerCamelCase, and the Elements nested within are separated by an underscore(_). Modifiers are separated by a double dash(--), and they are used for elements variants. An element's state is written separately with a pattern that begins with "_is_".

Variants are dissociated from states because they play a different role, and it appeared that with our components architecture, having a simple "_is_current" class for our items' "current" state was way more effective than a "mainMenu_item--current" when it came to modifying the state through javascript.
BEM modifiers are now exclusively used for visual variants that don't change over time. For example, if a tab needs to be highlighted so that it stand out, it is applied a variant.
By opposition, a "state" is something that is supposed to be handled by javascript and change over time.

Here is an example of what that convention may look like in our tab example :

// naming example
<nav class="mainNav">
    <ul class="mainMenu">
        <li class="mainMenu_item">
            <a class="mainMenu_link" href="#">Home</a>
        </li>
        <li class="mainMenu_item">
            <a class="mainMenu_link" href="#about">About</a>
        </li>
        <li class="mainMenu_item">
            <a class="mainMenu_link" href="#fileStructure">File Structure</a>
        </li>
        <li class="mainMenu_item">
            <a class="mainMenu_link" href="#components">Components</a>
        </li>
        <li class="mainMenu_item _is_current">
            <a class="mainMenu_link" href="#namingConventions">Naming conventions</a>
        </li>
        <li class="mainMenu_item">
            <a class="mainMenu_link" href="#responsive">Responsive</a>
        </li>
        <li class="mainMenu_item">
            <a class="mainMenu_link" href="#gettingStarted">Getting started</a>
        </li>
        <li class="mainMenu_item mainMenu_item--highlighted">
            <a class="mainMenu_link" href="#contributing">Contributing</a>
        </li>
    </ul>
</nav>
Note that this example is taken from the menu you're looking at just now in the present page.

At first, the BEM notation style can seem quite verbose and put off some developers, but it is very powerful and allows us to go way behind old school naming conventions.
It has to be tamed, though, and a classic beginner's mistake is to reflect the position of each element in the component's DOM in its class name. To avoid that, we recommend that you look at your low level elements first (those deeper in the DOM tree) and wonder if they could exist elsewhere in the page or in the component. Going up the tree, you can identify your most basic reusable components and set the names accordingly.

For example, in our example above, the "mainMenu_link" class doesn't need to reflect the fact that it is contained in a "mainMenu_item", this doesn't really matter to the link, so there is no reason to specify it in its name.

Sass files

We talked about some of the aspects of the Sass file naming convention in the "File Structure" section.

Each file is lowerCamelCase named and prefixed by an underscore(_) so that it is considered by the Sass compiler as a partial and not rendered to a standalone CSS file. The only exception to this rule is the components' standalone versions (see the "Components" section for details about this).

Each folder has a single entry point in charge of importing other partial Sass files. This file is named after the folder's name, and is prefixed with two underscores(__) so that it always appears on top in the files list. It imports only the files in its own folder, except for other summary index located in a direct subfolder. This way, you always can handle your imports very easily and stop the imports of nested files at any level.
Components definition files should have the same name as the component's folder name, and have a single underscore prefix.

Sass contents

For placeholders, used in the _helpers files or the components definitions, we recommend a mix of lowerCamelCase, dashes(-) and underscores(_). Helpers and components prefix should stick to lowerCamelCase, while components placeholders should include the component's prefix and separate sub parts from it with a dash or underscore. Sass treats dashes and underscores as if they were the same character, so they are totally invertible.

Note that those are only guidelines, and if for any reason you prefer to go with another convention in your project, you're free to do so. HTML classes and file names conventions have a rationale behind them which offers you some advantages, but for the sass files contents it's really just a matter of preference. We offer a suggestion only to provide some common ground for DoCSSa users.

For example, you could pass ".myExampleClass" as a selector to a component mixin for an implementation that would look like this :

// example
#{$selector} {
  @extend %componentName;
}
#{$selector}__singleItem {
  @extend %componentName__singleItem
  &:hover {
    @extend %componentName__singleItem-altState
  }
}

SASS variables

Sass variable names should be composed of dash(-) separated parts, with each part sorted from the most generic to the most specific variable characteristic. This is quite useful in most IDE as you can take advantage of autocompletion.

For example :

// variables example
/* _____ VARIABLES _____ */
// Generic
// ==========================================================================
$default-borderRadius: 4px;
$containerWidth: 760px;
$variant: 'base';
// Colors
// ==========================================================================
$color-default-black: #000;
$color-default-white: #fff;
$color-green: #449888;
$color-green-light: #5cbcaa;
$color-green-lighter: #a8d5cd;
$color-pink: #ee746f;
$color-grey-dark: #333;
$color-beige-dark: #c2c0bc;
$color-beige: #f1ede4;
$color-beige-light: #f8f5ec;
$color-code: #637c84;

Responsive

As you may have noticed, DoCSSa makes a quite heavy use of Sass placeholders. This is nice until you try to use them from within a media query, and stumble onto the dreaded "You may not @extend an outer selector from within @media. You may only @extend selectors within the same directive." error message.
But fear not, my friend! Until this gets fixed in Sass, there are ways around it.

In order to be able to use your components in any context, you'll only have a few things to keep in mind:

  • All breakpoints need to be named and predefined in the $breakpoints variable located in base/_config.scss
  • Placeholders definition need to be done through the provided _add() mixin
  • Placholders use need to be done through the provided _use() mixin
  • @media blocks need to be called through the provided breakpoint() mixin

If you respect this process, which is a bargain, you can enjoy helpers and components anywhere in your sass structure. Aren't you just glad you came ?

Here is how we implemented our "clearfix" helper for a responsive environment :

// in utils/_helpers.scss
@include _add(clearfix) {
  &:before,
  &:after {
    content: " ";
    display: table;
  }
  &:after {
    clear: both;
  }
  *zoom: 1;
}

As you can see, we just replaced the traditional %clearfix definition with @include _add(clearfix).

If you've already defined placeholders in DoCSSa before, a simple regex can do the conversion for you : replace %([^ {]+)\s*\{ with @include _add($1) { and you're done!

When creating the _add() mixin, we made sure it wouldn't break compatibility. That means that our clearfix placeholder can still be used with a simple @extend %clearfix as long as you're not within a media query block. But now, it can do much more!

First, you need to define the breakpoints :

// in base/_config.scss
$breakpoints: (
  "small": 600px,
  "medium": 900px,
  "large": 1200px
);

Once this is done, you can call the "clearfix" placeholder from within a media query with the following syntax:

// crossmedia placeholders example
.a {
  @include _use(clearfix);
}
.b {
  @extend %clearfix;
}
.c {
  @include breakpoint(medium) {
    @include _use(clearfix);
  }
}
@include breakpoint(medium) {
  .d {
    @include _use(clearfix);
  }
}
.e {
  @include _use(clearfix);
  @include breakpoint(large) {
    @include _use(clearfix);
  }
}

Here is what the end result would look like in your custom.css file :

@media (min-width: 900px) {
  .c,
  .d {
    *zoom: 1;
  }
  .c:before,
  .d:before,
  .c:after,
  .d:after {
    content: " ";
    display: table;
  }
  .c:after,
  .d:after {
    clear: both;
  }
}
@media (min-width: 1200px) {
  .e {
    *zoom: 1;
  }
  .e:before,
  .e:after {
    content: " ";
    display: table;
  }
  .e:after {
    clear: both;
  }
}
.a,
.b,
.e {
  *zoom: 1;
}
.a:before,
.b:before,
.e:before,
.a:after,
.b:after,
.e:after {
  content: " ";
  display: table;
}
.a:after,
.b:after,
.e:after {
  clear: both;
}

As you can see, everything ends up nicely in the correct media query, as if you had wrote it down manually. There is a little difference with the old school, hands in the dirt approach though: you can now have your logic in a single place, and stay DRY all the way!


Getting started

Download the kit

Download this page and its implementation of DoCSSa and play with it.
Source code can be found on DoCSSa's github page.

Learn about the basics

  • Handling Deferred Objects in DoCSSa [article]
  • Why DoCSSa ? [article]
  • Getting started with SASS [article]
  • Cross media query extend
  • Four ways to create CSS that's modular and scalable [article]
  • BEM methodology [official website]
  • Shubhie Panicker - CSS module system in Google+ (CSSconf.eu 2013) [video]

How to start ?

  1. First, you can simply write CSS code in separated files into the "specifics" folder, using DoCSSa's logic.
  2. Then, try manipulating the provided "_helpers" and "_mixins" from the base/utils folder to give your project more reusable code.
  3. After that, you may write your own "_helpers" and "_mixins", tailored for your own specific needs.
  4. For more reusability within or across your project(s), you may then try to convert some of your "specifics" rules into "components".
    If see you are repeating the same rules on different sets of classes, you have a good candidate.
  5. Cherry on the cake, you can finally add responsive super powers to your components.
  6. Been there, done that ? It's time to preach the choir ;)

I'm the team lead of a non expert koala army, how can I make use of DoCSSa's powers ?

  1. While your koalas are learning Sass, they can keep writing the same old CSS in 'specifics' folder
  2. Once one of them feels ready to, let her write "_helpers", and let the whole team know they can use them.
  3. It won't be long before some other koalas would like to write _helpers or _mixins.
  4. With knowledge adding up, it will become easier to detect components candidates.
  5. Don't forget to offer your koalas a lot of eucalyptus regularly.

Contributing

Contact us

DoCSSa is evolving!
We are very interested in your feedback to improve it or learn about how you implemented it.
Please contact us, fork the project, make Pull Requests or talk about DoCSSa at will.