- About this Guide
- Naming Conventions
- Comments & Whitespace
- Creating Selectors
- Nesting
- Media Queries
- Helper classes
- When you can not edit the HTML markup
- Summary & General Rules
- Credits, Sources, Further Reading
When starting out in a new codebase, or writing a new section of CSS, there can be a lot of hesitation and uncertainty — "Is this the best way to do this?" "Am I doing this right?"
Our goals in writing this guide are:
- Eliminate guesswork when writing styles
- Provide consistancy where Bootstrap is inconsistant
- Help developers who are new to CSS get started in the right direction
At a high-level, your goals in writing CSS for Rock should be:
- Create a library of reusable modules (or blocks) instead of styling specific pages and modules
- Write styles with developer usability in mind
Note: at time of writing, our current codebase does not always follow these guidelines. We're aware of this and are making plans to refactor it.
A mix of BEM (a naming convention meaning block, element, modifier) and Bootstrap's conventions. More on this in section 5.
.blockname-elementname-modifiername
// Example
.footernav
.footernav-col
.footernav-col-big
We seperate our javascript hooks from styling hooks to prevent accidental breakages, and allow more confidence in style refactoring.
.js-hookname
// Example
.js-loginbtn
Never style a .js- class — and don't use style classes for selectors in Javascript, either.
//
// Heading 1 (2 blank lines above, 2 below)
// --------------------------------------------------
// Heading 2 (2 above, 1 below)
// -------------------------
// Heading 3 (2 above, 1 below)
- 2 space soft indent
- Why? Standard used by Bootstrap, renders consistently wherever used.
- No trailing whitespace
- Use the EditorConfig plugin to have your IDE take care of most of this. Visual Studio users can install this using the extension manager.
- Also called BEM
- Blocks have sub elements, 1 level deep
- Example:
.person
.person-head
- No:
.person-head-eye
- Yes:
.person-eye
- Blocks and Elements can have modifiers
.person-tall
.person-eye-blue
Don't modify the properties of a class based on it's location. Instead, add an optional class that adds the desired changes.
- Example
- No:
.footer .menu { color: white }
- Yes:
.menu-light { color: white }
- No:
In this example, .menu has a different color simply becuase it is located in a different position within the HTML markup. Essentially, the styles for this specific module now live in two different areas — creating potential headaches later on. A more future oriented solution is to add another class to the HTML to achieve the same effect.
There are many reason why it's a bad idea — mainly, it's practically impossible to override without using !important
. The benefits just don't outweigh the disadvantages.
If you have to style third party code that does use ID tags, try using an attribute selector instead [id=“vendor-thing”] { … }
Use the least amount of specificity necessary. The more specific your styles are, the increasingly harder it will become to extend and modify them later.
Dont use ul.footernav
if you can use .footernav
instead.
LESS (and other preprocessors) make it easy nest your styles. It can be very convenient, but it's overuse can lead to styles that are more specific than necessary. It's easy to lose track of how long (and specific) a selector has become when you're 5 levels deep.
- Try to limit your nesting to 3 levels at most
- Instead of nesting submodules, indent entire selectors to simulate their hierarchy in HTML
// No
.footernav {
[...]
.footernav-col {
[...]
.footernav-header { [...] }
}
}
// Yes
.footernav {
[...]
}
.footernav-col {
[...]
}
.footernav-header { [...] }
- Keep media queries close to the styles that they effect, not in a seperate stylesheet.
- Use our media query helpers
@xs = (min-width: @screen-xs-min) = 480px
@sm = (min-width: @screen-sm-min) = 768px
@md = (min-width: @screen-md-min) = 992px
@lg = (min-width: @screen-lg-min) = 1200px
// Example
@media @xs {
.footernav {
padding: 2em;
}
}
Aim to build your styles and their respective media queries mobile first: styles for mobile are the base styles, and media queries are used to provide styles for the larger screen sizes. This isn't always feasible, but it will help you and other developers in the future.
// Yes
.block { padding: 1em; }
@media @sm {
.block { padding: 2em; }
}
@media @lg {
.block { padding: 4em; }
}
// No
.block { padding: 4em; }
@media (max-width: 1199px) {
.block { padding: 2em; }
}
@media (max-width: 992px) {
.block { padding: 1em; }
}
Helper classes are single responsibility classes or variables that can be combined with reusable modules, or added into a glue layer, to acheive the styles you're looking for.
See #6
Our margin and padding helpers follow a basic pattern:
[margin/padding]-[side: t,b,r,l,v,h,all]-[size: sm,md,lg,xl]
Side values
- Top
- Bottom
- Right
- Left
- Vertical (top & bottom)
- Horizontal (left & right)
// Examples of actual classes
.padding-b-md
.margin-l-xl
<!-- Usage Example -->
<div class="margin-v-lg">[...]</div>
We use some spacing variables that are based of off bootstraps own variable: @grid-gutter-width
. We multiply or divide this variable to create complementary pixel values.
// Our Helpers
@spacing-sm-px // Default: 7.5px
@spacing-md-px // Default: 15px
@spacing-lg-px // Default: 30px
@spacing-xl-px // Default: 60px
Using spacing variables can help you create designs that have consistent spacing and vertical rhythm.
One of the goals when writing CSS for Rock is to create reusable modules. If you can control the markup of the HTML, this is easy to implement. If you have to use markup that is already set, and possibly unchangeable, it becomes more of a problem.
There are two ways to work around this:
- Duplicate the Rock Block and modify the markup (make sure you know what you're doing)
- Create a 'glue layer' between your reusable modules and the uneditable markup
With a glue layer, you add mixins (can be regular CSS classes), to specific class. When compiled by LESS, all of the styles from these classes will be added, or mixed-in.
// Example
.some-rock-block-header {
.footernav-heading;
}
.some-rock-block-wrapper {
.container;
}
.some-rock-block-button {
.btn;
.btn-default;
.pull-right;
}
Note: this method creates a bit of duplication in your stylesheets. This is something we would normally avoid, but there are not too many alternatives here.
- Select what you want explicitly, rather than relying on circumstance or coincidence. Good Selector Intent will rein in the reach and leak of your styles. (.sub-header instead of .content h2)
- Write selectors for reusability, so that you can work more efficiently and reduce waste and repetition. (.highlight-color instead of .blue)
- Do not nest selectors unnecessarily, because this will increase specificity and affect where else you can use your styles. (.footernav-col instead of .footer .sidebar .nav .col)
- Do not qualify selectors unnecessarily, as this will impact the number of different elements you can apply styles to. (.nav instead of ul.nav)
- Keep selectors as short as possible, in order to keep specificity down and performance up.
- When in doubt, bootstrap wins. If it’s not clear in this style guide, do what Bootstrap does.
Most of the work is inspired, similar, or copy and pasted directly from articles by really talented individuals.