Friday, October 30, 2015

Using PostCSS with BEM and SUIT Methodologies

In this tutorial we’re going to learn how to use PostCSS to make development of BEM/SUIT style CSS easier and more efficient.

These two methodologies lay out a naming convention for classes that makes it easier to keep your styles tightly function-oriented, and helps other developers recognize the purpose of various classes just from the way they’re named.

BEM was the forerunner of this type of class naming methodology, created by Yandex. The SUIT methodology is an approach based on BEM, but with some adjustments and additions made by Nicholas Gallagher. SUIT does everything BEM does, but to many users it is considered an enhancement.

Working with these methods definitely helps to produce better, more well structured CSS. However, the tricky part is that it can become tiresome manually typing out the class names required in this structure, and keeping track of how classes inter-relate can become a bit of a headache. 

The postcss-bem plugin by Malte-Maurice Dreyer alleviates these issues through a combination of shortcuts and nesting, which you will learn to use as we move through this tutorial.

But first, let’s have a quick primer on the BEM and SUIT methods, to make sure you have a clear picture of the benefits of using the postcss-bem plugin, and of the way it’s used.

Quick Primer on BEM

Block

In BEM blocks are high-level chunks of a design; the building blocks the site is made from. A block should be a piece of your site that’s independent of other pieces, and could theoretically be placed anywhere in your layout, even nested inside another block.

For example, search form “blocks” on your site might use the class .search-form.

Element

An element in BEM is a subsection inside a block. They are signified by appending a two underscore __ separator and an element name to the parent block name.

For example, a search form might include heading, text field and submit button elements. Their class names might be .search-form__heading.search-form__text-field and .search-form__submit-button respectively.

Modifier

A modifier is applied to a block or element to signify a change in its presentation, or a change in its state. They are signified by appending a separator and a modifier name to the block or element in question.

The official BEM site docs state that modifier separators should be a single underscore _. However the "BEM-like" convention of CSS Guidelines by Harry Roberts employs two dashes -- and is probably more widely used and known than the official BEM convention.

For example, in a design you may wish to present advanced search forms differently to regular search forms, and hence create the modifier class .search-form_advanced (official BEM) or .search-form--advanced (BEM-like).

In another example, you might want to change the form’s appearance due to a change in state, such as if invalid content has just been submitted, and hence create the modifier .search-form_invalid (official BEM) or  .search-form--invalid (BEM-like).

Quick Primer on SUIT

SUIT comprises Utilities and Components. Within components there can be Modifiers, Descendants and States.

SUIT uses a combination of pascal case (PascalCase), camel case (camelCase) and dashes. Its conventions enforce a limit on the sometimes confusing number of dashes and underscores that can appear in BEM. For example, the BEM class .search-form__text-field would be .SearchForm-textField in SUIT.

Utility

Utilities handle structure and positional styling, and are written in such a way that they can be applied anywhere in a component. They are prefixed with u- and written in camel case. For example, .u-clearFix.

Component

A component in SUIT takes the place of a block in BEM. Components are always written in pascal case and are only part of SUIT that uses pascal case, making them easy to identify. For example, .SearchForm.

Component Namespace

Components can optionally be prefixed with a namespace and single dash nmsp- to ensure conflicts are prevented, e.g. .mine-SearchForm.

Descendent

A descendent in SUIT replaces an element in BEM. It uses a single dash - and is written in camel case. For example .SearchForm-heading.SearchForm-textField and .SearchForm-submitButto.

Modifier

SUIT uses modifiers as does BEM, however their role is more tightly controlled. A SUIT modifier is generally only applied directly to a component, not to a descendent. It should also not be used to represent state changes, as SUIT has a dedicated naming convention for states.

Modifiers are written in camel case and are preceded by two dashes --. For example,  .SearchForm--advanced.

State

State classes can be used to reflect changes to a component’s state. This allows them to be clearly differentiated from modifiers, which reflect modification of a component’s base appearance regardless of state. If necessary, a state can also be applied to a descendent.

States are prefixed with is- and are written in camel case. They are also always written as adjoining classes. For example  .SearchForm.is-invalid.

Setup Your Project

Now that you have the essentials of BEM and SUIT down, it’s time to setup your project.

You’ll need an empty project using either Gulp or Grunt, depending on your preference. If you don’t already have a preference for one or the other I recommend using Gulp as you’ll need less code to achieve the same ends, so you should find it a bit simpler to work with.

You can read about how to setup Gulp or Grunt projects for PostCSS in the previous tutorials

respectively.

If you don't want to manually setup your project from scratch though, you can download the source files attached to this tutorial, and extract either the provided Gulp or Grunt starter project into an empty project folder. Then with a terminal or command prompt pointed at the folder run the command npm install.

Install Plugins

Next, you’ll need to install the postcss-bem plugin. We'll also be installing a plugin that can work in with it quite well: postcss-nested.

Whether you’re using Gulp or Grunt, run the following command inside your project folder:

Now we’re ready to load the plugins into your project.

Load Plugins via Gulp

If you’re using Gulp, add these variables under the variables already in the file:

Now add each of those new variable names into your processors array:

Do a quick test that everything is working by running the command gulp css then checking that a new “style.css” file has appeared in your project’s “dest” folder.

Load Plugins via Grunt

If you’re using Grunt, update the processors object, which is nested under the options object, to the following:

Do a quick test that everything is working by running the command grunt postcss then checking that a new “style.css” file has appeared in your project’s “dest” folder.

Okay, you’re ready to go. Let’s learn how to generate BEM and SUIT structure.

BEM and SUIT with postcss-bem

There can be some unwieldiness developing in BEM or SUIT structure when writing code out manually, as continually repeating the same identifiers in class names can become tiresome, and keeping track of which elements and descendents belong to which blocks and components can get confusing.

When you use postcss-bem however, it becomes easy to make sense of the structure of your code at a glance, and repetition in typing out class names becomes virtually non-existent.

Generating SUIT Structure

Despite its name, by default postcss-bem will output according to SUIT syntax rather than BEM. You can output in BEM syntax, which we will cover later, but the plugin is primarily designed to output SUIT, so for that reason, we’ll start with SUIT syntax.

Generating a Component

To create a component, use the syntax @component ComponentName {...}.

Try this out by adding a SearchForm component to your “src/style.css” file:

Compile it and your resulting code should be:

Generating a Descendent

To create a descendent, use the syntax @descendent descName {...} nested inside the parent component.

Add a descendent named textField inside your SearchForm component like so:

After compiling, you should now see:

Generating a Modifier

Create a modifier to a component with the syntax @modifier name {...}, nested inside the component it effects. Modifiers should typically be placed at the top of your component, above any descendents and states.

Add a modifier named advanced to your SearchForm component with the following code:

Recompile your code and you should see your new advanced component modifier:

Generating a State

States are created via the syntax @when name {...} and can be nested inside a component or a descendent.

Add a state named invalid to your textField descendent using this code:

Now when you compile your code you’ll see it contains your new invalid state:

Namespacing Components

You can namespace your components, and all the descendents, modifiers and states nested within them, by surrounding them with @component-namespace name {...}. You can, if you like, wrap your entire stylesheet with this namespace so all your classes are automatically prefixed with it.

Try this out by wrapping all your code so far with @component-namespace mine {...}:

After compiling, you’ll see that now every one of your components is prefixed with mine-:

Generating a Utility

Utilities are created with the syntax @utility utilityName {...}. You’ll recall that when setting up your project, you installed the postcss-nested plugin. We did this as it can be very handy to use in unison with postcss-bem, as you’ll see in this example where we create a clearFix utility:

After adding the above code, compile and you’ll see this new utility has been created:

Generating BEM Structure

To activate BEM syntax output in postcss-bem, pass the option style: 'bem' in your Gulpfile or Gruntfile like so:

By default postcss-bem will use the official separator for a modifier of a single underscore _. If it’s important for your project that you use the more common separator of two dashes -- instead, you can change the config for the postcss-bem plugin by going to the node_modules/postcss-bem folder of your project, opening up index.js, locating line 15 and changing this:

...to this:

Generating a Block

Because a “block” in BEM correlates with a “component” in SUIT, use the syntax @component block-name {...} to generate a block.

To create a search-form block add this code:

Then compile and you should see:

Generating a Element

As an “element” in BEM correlates to a “descendent” in SUIT, they can be created with the syntax @descendent element-name {...} nested inside the parent block.

To create a text-field element add the following:

On compilation, you’ll see your new element has been created:

Generating a Modifier

Even though BEM allows modifiers to both blocks and elements, the postcss-bem plugin will only process them if nested inside blocks and not elements, due to the SUIT convention of modifiers being applied to components not descendents. They can be created with the syntax @modifier name {...}, nested inside its parent block.

Add an advanced modifier to your search-form component like so:

And on compilation it will yield:

No Utilities or States, but Namespaces Are In

While in BEM mode the @utility and @when syntaxes will not compile into anything, given BEM does not use utilities or states.

However, even though it’s not generally part of BEM, the @component-namespace syntax will still work if you wish to use it in your BEM stylesheet. It will prefix your classes with name--:

Let’s Recap

Now you know all about how to shortcut your BEM and SUIT development, and make the overall process more easier. Let’s summarize everything we’ve covered:

  • BEM and SUIT are class naming conventions that help to keep stylesheets function oriented and organized, as well as helping other developers recognize the purpose of various classes.
  • SUIT is like BEM, but with some extras added and adjustments made
  • The postcss-bem plugin provides shortcuts for creating BEM and SUIT classes, such as @component, @descendent, @modifier etc.
  • The plugin also allows code to be nested in a helpful way, e.g. modifiers are nested inside the component or block they modify.
  • Namespacing can be done automatically by wrapping classes with @component-namespace name {...}

In the Next Tutorial

Coming up next we look at another great way to take advantage of PostCSS, and that is by putting together a toolkit of shorthand and shortcuts we can take to make our coding faster and more efficient.

I’ll see you there!


by Kezz Bracey via Tuts+ Code

No comments:

Post a Comment