Loading repository data…
Loading repository data…
gilbox / repository
A CSS style guide that puts the Clean, Smart, and Simple back into CSS
A CSS style guide for small to enormous projects, without all that pomp and cruft. Many ideas borrowed from BEM, SMACSS, OOCSS, SUITECSS. This style guide uses SCSS. However, the only truly beneficial preprocessor-specific features we discuss are variables, mixins, and partials. Therefore, this guide will be useful for any preprocessor or no preprocessor at all as there is very little focus on features that aren't already part of vanilla CSS.
There is now a Walkthrough. If you have never used BEM, SMACSS, or similar, reading the Walkthrough is highly recommended.
There is now a linter.
Enforcing css-bliss rules without it is very difficult.
If you have questions, comments, or suggestions please open an Issue. And of course, PRs are welcome.
.MyModule-myElement--myModifier[ pen ] links as you encounter them below.TitleCase Modules, camelCase Elements. why-not-dashes ? Because cased names are more readable (very objective explanation, I know). Furthermore, if we see a class name that doesntStartWithTitleCase we know that it's not a module.
Note: The following example does not match the conventions laid out in the DRY section because this is the compiled CSS code, not the SASS code.
.MyModule {
...
}
.MyModule-myElement {
...
}
.MyModule-myElement--modifier {
...
}
.MyModule--modifier .MyModule-myElement {
...
}
.MyModule.isState {
...
}
.mySimpleRule {
...
}
.TitleCase@extended to create Module Modifiers--camelCase@extend a Module to create a Module Modifier@extend a Module Modifier to create another Module Modifier-camelCase.MyModule-myElement--camelCase.MyModule-myElement--myModifier.isCamelCase (formerly .is-camelCase).MyModule.isState, .MyModule-myElement.isState, .MyModule-myElement--myModifier.isState, .isState .MyModule-myElement, etc..camelCase.may-containDashes when the dashed word might imply very similar meaning as a function argument does in javascript. A good use-case for dashed utility classes are device-specific classes such as .col2-mobile, .col2-tablet, etc.Modules promote strict encapsulation. We achieve encapsulation thusly:
.is) classes)When choosing class names, try to ignore function, and concentrate on style. Just because we have a section on our website named music doesn't mean that we should name our music-related card Module MusicCard. Sure, we can name it MusicCard if similar cards do not appear anywhere else on the website. Otherwise, name it Card instead. (Since we probably can't know for sure whether the same card might later be added to a new section of the site, when naming classes make a judgement call based on the information available at the time and don't try to plan too far into the future.)
And now that we have our Card module, if we need a modifier for a green-tinted card in the section we're currently working on (which happens to be the music section) name it Card--greenTint. If your modifier truly is specific to the music section then Card--music is OK when a more stylistically descriptive name doesn't present itself.
There is a lot of seemingly conflicting information about CSS semantics. Some people say to name your class by function like this:
<div class="FacebookBtn">FB</div>
instead of
<div class="Btn">FB</div>
However, we favor the second approach. Using the .FacebookBtn class name is convenient when you're using a library like jQuery because it keeps your markup and jQuery selector code semantically correct. However, with HTML5 and modern frameworks like angularjs the markup is already semantically correct via the use of custom element naming, attributes, and event handlers which declaratively describe the content and its function.
What about our Jasmine unit tests which are heavy with jQuery selectors? If class names are un-semantic does that force us to write unit tests that break when simple stylistic changes are made to the interface? Not if we favor the use of attribute and element selectors in our unit tests which generally means the tests will only break when functionality changes.
Above each Module, describe the purpose of the Module, as well as it's scope. Be restrictive and specific so that when someone else looks at it and needs to add some styling, they will know if they should add-on to the Module or create a new one.
// A floating dialog with dropshadow, rounded borders, and a header.
// Includes the header text, but not any buttons and none of the other content inside of the dialog.
.PopupDialog {
...
}
Note that in the example above, the comment answers the question, what is and isn't a PopupDialog Module allowed to style?. Later, if one of our teammates wants to add a close button to this dialog, they can read this comment and determine that the close button should probably be a Module in it's own right, and not an element of the PopupDialog module.
%MyModule-placeholderDescriptorThe next section discusses why we should avoid using @extend. However if we do use @extend despite our trepedations, we will try to restrict its use to placeholders. And as we should with any @extended class, keep %placeholders flat, here's why.
%placeholder {
// avoid nesting .anyClassRules at any cost...
.dontDoThis { ... }
}
%placeholders should be small pieces of reusable styling, and they should do one thing and do it well.
Don't @extend Modules to create Module Modifiers because
@extend can result in more code than simple subclassing@extend is incompatible with media queries@extend makes understanding the cascade of SCSS code very difficultWhat about using @extend in other rules? In most cases, using @extend can lead to confusion and should probably be avoided.
When a @mixin is declared inside of a Module:
@MyModule-mixinDescriptorWhen a @mixin is declared outside of a Module:
@mixinDescriptorWhen a $variable is declared inside of a Module:
$MyModule-variableDescriptorThe purpose of this rule is to make it easy to identify local vs global variables.
.MyModule {
...
&-myElement {
...
}
&-myOtherElement {
...
}
&-myOtherElement--myModifier {
...
}
&-myOtherElement--anotherModifier {
...
}
}
and module modifiers:
.MyModule--myModifier {
...
.MyModule-myOtherElement {
...
}
.MyModule-myOtherElement--anotherModifier {
...
}
}
A downside is that doing a full-text search for a class won't take us where we need to go, but if the naming convention is well-established we'll have that in mind when searching anyway.
This DRY approach prevents @extending Elements and Element Modifiers. This is good because @extending these nested classes creates confusing and difficult to maintain code.
Create a new file for each Module and it's Module Modifiers and save inside of the modules directory. Use TitleCase naming for module files and dashed-names for everything else. Th