Avoiding CSS conflicts
Introduction
When your system is composed of HTML responses from multiple apps, there's always a risk of naming conflicts and cascading side effects in your CSS. A solution to this is to use a convention that isolates styles coming from different apps.
We recommend BEM, a well-known convention that solves this problem.
What is BEM?
In the BEM naming convention, you only use classes in your stylesheets. There are three kinds of classes at your disposal: blocks, elements, and modifiers.
A block is a basic class that represents a logical area of your app's UI (a menu, login form, a search form).
An element is a part of a block that performs a particular function (a link in the menu, a password input in the login form, a search icon).
A modifier is a variation of a block or of an element (an expanded menu, an active menu item, a password input with an invalid value, a disabled search button).
Possible combinations of blocks, elements and modifiers are the following:
When applied to an HTML structure, the above CSS class names are used in the following way:
Note here that everything at the root level must be a block. A block can have multiple element and modifier sections and every element and modifier has to belong to a block.
Example
Consider the SignIn app:
Here, the block is marked in red and the element sections in blue.
From this, these BEM classes can be derived:
Check out the source code of People or KitchenSink. These sample apps show how to apply BEM in practice.
BEM in Starcounter apps
We recommend the following rules when using BEM selectors in Starcounter apps.
Only use BEM class selectors in your stylesheets. Do not use element selectors, id selectors, or inline styles for the purpose of styling.
Give meaningful names to the block, element and modifier sections. For example,
.chatter-avatar
is much more descriptive than.chatter-img
.Use resusable names for the block, element, and modifier sections. As seen in the example above,
.signin-form__text-input
is preferred over.signin-form__firstname-input
sincetext-input
is more resusable thanfirstname-input
.Prefix block sections with the app name to isolate your classes from other apps. For example, the class for a menu block in the "Chatter" app should be
.chatter-menu
.Use lowercase classes.
.Chatter-Menu
is wrong,.chatter-menu
is right.Separate words with a hyphen when there are multiple words in a block, element or modifier section. For example:
.chatter-chat-message__message-text
.Block and element must be in the same HTML template. Otherwise, implicit couplings are created between templates which might break when the partial mapping changes. If you want to define
.chatter-menu
in a parent partial and the menu items in a nested partials, these menu items will become new blocks (.chatter-menu-item
, not.chatter-menu__item
).Modifier classes should extend base classes.
When you set a
.chatter-menu__item--active
class on an element, it should not be needed to add the.chatter-menu__item
base class.In your stylesheet, the definition for the base class should include all the modifiers, like this:
Never nest blocks inside blocks and elements inside elements.
If there’s need for more nesting, it means there’s too much complexity and the elements should be stripped down into smaller blocks.
Mixing BEM with Bootstrap
Starcounter sample apps use the CSS framework Bootstrap to create a unified look and feel.
Even though Bootstrap does not follow BEM, there are no issues with mixing Bootstrap and BEM in a single project because there are no collisions. In fact, by just looking at the class, you can immediately tell if that class is shared with other apps (Bootstrap) or if it's private to this particular app (BEM).
It is not fine to override Bootstrap classes in your app's stylesheet. The only proper way to extend style is to with a BEM selector, for example:
For reference, the available Bootstrap classes can be found in bootstrap.css.
Further reading
Last updated