While trying to find a solution for handling CSS in upcoming Baasic starter kits, we came up with a simple and interesting solution. Since we didn’t want to impose a particular preprocessor technology such as SASS, LESS or Stylus to our users, we’ve built a CSS workflow that utilizes the most helpful preprocessor features such as code blocks, modularity and CSS variables with just a little help from a postprocessor. You can now use plain CSS and have the ability to switch easily to SASS, LESS or Stylus - whenever you want to do it.

Everybody knows plain-old CSS, so we took it as a starting point. Pure CSS workflow is great to handle since it is a standard and is dependency-free but lacks modularity and is hard to maintain.

The idea was to take the best of the both worlds - to build a modular CSS environment respecting DRY, object oriented and BEM principles without a lot of dependencies. The usage of Pleeease as a postprocessor gave us the features we were missing.

Pleeease postprocessor

Pleeease is a Node.js application that easily process your CSS. It can:

  • preprocess CSS (experimental)
  • add prefixes, based on Autoprefixer
  • provide fallbacks for rem unit, CSS3 pseudo-elements notation
  • add opacity filter for IE8
  • convert CSS shorthand filters to SVG equivalent
  • pack same media-query in one @media rule
  • inline @import styles
  • minify the result

Also, Pleeease.NEXT version goes even further and allows you to use some of the future CSS’s features today:

  • provides fallbacks for CSS custom properties (aka CSS variables) and custom media-queries
  • reduces calc() whenever possible
  • adds some features from CSS4 colors module: color(), hwb(), #RRGGBBAA notation and more

Pleease supports CSS, SCSS, LESS and Stylus syntax, so this environment can be used with any of these technologies.

Building code blocks

Our setup allows us to bundle CSS files on output, so we can write separate modular logical code blocks, as shown below:

CSS file structure

We have divided CSS into small and logical code blocks to make them easier to overview and maintain. We use .vars for variables, .tools for externals, .modules for reusable code, .components for specific elements, etc.

Now we will use the @import rule to import these code blocks into a single file named app.css:

/*------------------------------------*\
    # Application CSS file
\*------------------------------------*/


/*
* Variables
*/

@import url("vars.defaults.css");

/**
 * Tools 
 * Various tools
 */

@import url("tools.fontface.css");

/**
* Generic styles
* Default style setup for reseting or normalizing our CSS
*/

@import url("generics.normalize.css");
@import url("generics.boxmodel.css");

/**
 * Base styles
 * The base global classes and styling
 */

@import url("base.globals.css");
@import url("base.typography.css");


/**
* Project specific modules
* All our modules such as buttons, inputs, labels, tables etc. 
*/
@import url("modules.buttons.css");
@import url("modules.navigation.css");

/**
* Project specific components
* All project components such as headers, footer, bars, dropdowns etc.
*/


@import url("components.layout.css");
@import url("components.header.css");
@import url("components.footer.css");


/**
* Common classes
* Class helpers such as push, pull, radius etc.
*/


@import url("util.floats.css");
@import url("util.visibility.css");

This part is essential for our approach, because it keeps your code organized, easy to understand and easy to edit. Also, it is good to follow DRY and BEM principles, as the resulting CSS workflow should be easy to follow and maintain.

Using variables

To increase the speed of development and the overall code quality, we can use CSS variables, since Pleease outputs their values.

/*------------------------------------*\
    # vars.colors
\*------------------------------------*/

:root {
    --color-primary:     red;
    --color-secondary:   gray;
}

We can put all sorts of values into variables, including colors, numeric values, font families, etc. Variables are extremely valuable for CSS maintenance and reliability purposes.

Vendor prefixes

Vendor prefixes are added automatically using Autoprefixer that comes bundled with Pleeease, based on your configuration settings.

/*------------------------------------*\
    # modules.buttons
\*------------------------------------*/

.btn {
    border-radius: 3px;
}

will output:

.btn {
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
}

Media Queries

We use custom media queries for handling media queries. We’ve added predefined variables for breakpoints that you can use.

/*------------------------------------*\
    # vars.responsive
\*------------------------------------*/

@custom-media --from-small (min-width: 20em);
@custom-media --from-medium (min-width: 48em);
@custom-media --from-large (min-width: 64em);

usage:

.btn {
    width: 100%;
}

@media (--from-medium) {
    .btn {
        width: 50%;
    }
}

Configuring Pleease

To make it all work, you need to setup Pleeease by creating a configuration file. You can find instructions for that here. After you configure Pleeease, you just need to compile or watch by running:

$ pleeease compile

or

$ pleeease watch

Baasic starter kits use gulp to do this, so you can just run

$ gulp serve

to start Pleease watch. Pleease will now replace variables, add vendor prefixes, bundle and minify your CSS.

Configuration file for Baasic starter kits looks like this:

{
  "browsers": ["last 2 version"],
  "filters": true,

  "minifier": true,
  "mqpacker": false,
  "sourcemaps": false,
  "next": true
}

CSS rocks

Simplicity and avoidance of preprocessor technologies syntax were our main guidelines while developing this workflow. We hope you will be able to use it in your own projects no matter which preprocessing technology you use - if you use any. As always, please send us your comments or questions.

Feel free to leave a comment

comments powered by Disqus