(Largely cribbed from GitHub's Styleguide)
- Use soft-tabs with a two space indent. Spaces are the only way to guarantee code renders the same in any person's environment.
- Put spaces after : in property declarations.
- Put line breaks between rulesets.
- When grouping selectors, keep individual selectors to a single line.
- Each declaration should appear on its own line for more accurate error reporting.
- Use // for comment blocks (instead of /* */).
- Avoid specifying units for zero values, e.g., margin: 0; instead of margin: 0px;.
- Use the white-space, Sass syntax, not the CSS-superset SCSS syntax
- Whenever possible, use a variable for colors and font-sizes, rather than literal values
- Declare any
@extend something-else
or+mixin
at the top of your rules, followed by properties and nested selectors, separated by an empty line
// Good
.DishHero
@extend %dish-media-object
@include border-radius
padding-bottom: $padding-s
margin-bottom: $padding-m
border-bottom: 1px solid $border-color
// psuedo-classes of the current selector should be declared _before_ child selectors
&:hover
background: $highlight
img
@extend %media-object
// more properties
// repeat as needed
// Bad
.DishHero
padding-bottom: $padding-s
margin-bottom: $padding-m
@extend %dish-media-object
border-bottom: 1px solid $border-color
@include border-radius
img
// more properties
@extend %media-object
Observe the "Inception Rule": Don’t go more than four levels deep. Try to keep it to three levels, reserving the fourth level for pseudo-classes (i.e. :hover
or :active
)
// Bad
.reality
.van-chase
.hotel
.snow-fortress
// this is a stretch
.limbo
// don't do this
// Good
.ChefsFeed
.title
a
color: $black
&:hover
color: $blue
Media queries should be nested inside the selector they modify, not outside.
(Sass cannot extend a selector that is nested under a media query. This mainly affects only %
placeholder selectors, but we should be consistent.)
// Good
.restaurant_photos-multi_edit
.user-content-wrapper
@include screen-md
display: flex
flex-wrap: wrap
// Bad
.restaurant_photos-multi_edit
@include screen-md
.user-content-wrapper
display: flex
flex-wrap: wrap
Take media queries into account when observing the Inception Rule; media queries nest, and should therefore be treated as a new level.
// Bad
.reality
.van-chase
// styles
@media $hotel
.snow-fortress
// this is a stretch
.limbo
// don't do this
// Good
.ChefsFeed
.title
a
color: $black
&:hover
color: $blue
@media $small-screen
// styles are OK here, but don't nest anymore selectors
stylesheets/responsive
├── abtests
├── addons
├── base
├── ie_sass
├── layouts
├── modules
├── patterns
├── vendor
├── _config.sass
├── _sketch-pad.sass
└── application_responsive.sass
With the exception of addons
each directory contains a file named _index.sass
which serves as a manifest for that directory; all files in the directory should be @import
'ed in _index.sass
.
abtests
contains styles for currently running A/B testsaddons
contains styles for third-party widgets and plugins. Alladdons
files that are compiled to stand-alone CSS filesbase
contains the basic, elemental stylingie_sass
contains styles for IElayouts
,modules
,patterns
contain styles for the respective layers (see Larger principles below)vendor
contains a manifest of third-party styles that required by our application styles (i.e. Bootstrap)
All filenames should begin with an underscore (_
).
Files should be named after their top-level selectors. If your top-level selector is .my-awesome-selector
, your file should be named _my-awesome-selector.sass
Within modules and patterns you may find yourself with a need for more than a single file. For example, the block-grid
pattern is more complex, so the Sass for that pattern is broken into separate files in a sub-directory of patterns/
stylesheets/responsive
├── patterns
| ├── block-grid
| | ├── _functions.sass
| | ├── _index.sass
| | ├── _mixins.sass
| | └── _placeholders.sass
Again, _index.sass
serves as a manifest of the files composing this pattern.
Within modules, sub-directories can server to group concerns. For example, the modules/dish
directory contains a number of files all relating to the styling of dishes.
Module and layout files should consist of only one top-level selector.
// Good:
// modules/_dimmi_reservation.sass
.DimmiReservation
.form-group
@extend %col-sm-3
margin-bottom: $padding-x
@include screen-sm
margin-bottom: 0
.make-reservation-btn
@extend %btn
@extend %btn-primary
@extend %btn-block
margin: 0 $padding-sm
width: auto
.form-control
margin-bottom: 0
// Bad:
// modules/menu/_menu_photos.sass
.MenuPhotos-primary
ul
@include block-grid(4)
.AddMenuPhoto
background: image-url('1/menu-background-blur.jpg') no-repeat 50% 50%
line-height: 1.1
+screen-xs
font-size: 20px
&:hover
text-decoration: none
color: white
&:after
content: ""
left: 50%
margin-left: -150px
(An exception to this rule would be if your top-level selector is a placeholder, which you then immediately @extend
, as in modules/dish/_dish_grid.sass
. But this is relatively rare in modules and non-existent in layouts.)
Base and pattern files can contain multiple top-level selectors. Top-level selectors in pattern files should always be placeholders—patterns should never output literal CSS.
Base top-level selectors should be either HTML elements (p
, a
, table
, etc.) or placeholders, they should not be classes or IDs.
(Our current code base does not meet these standards, but that should not stop us from implementing these standards on new code.)
Where possible, avoid IDs as selectors, whether at the top level or nested. There will be exceptions to this rule, of course, but if you choose an ID as your selector, have a good reason.
When naming a selector favor clarity over brevity; .primary-button
is better than .btn--p
.
Bootstrap is based on OOCSS principles.
Object-oriented CSS tries to "solve" CSS by emulating the idea of OOP. It does this by breaking styles down to the smallest possible parts and putting them in separate classes. So we end up with class chains like this in our markup:
<button class="btn btn-primary btn-green btn-large">Save</button>
That's a lot of classes that don't really describe our button.
Semantic naming
<button class="save">Save</button>
Principles of a semantic, modular CSS architecture:
Visual elements are the basic building blocks of the UI. Well engineered individual elements reduce duplication and increase consistency.
Elements include: typography, colors, buttons, grid, etc.
Sass for elements that map directly to HTML elements (hN
, p
, header
, etc.) would output actual CSS, while Sass for things like buttons or the grid should be implemented as placeholders.
Patterns are small abstract units of frequently used styles.
Patterns include: an input with a label, field set presentation, and other commonly occurring styles.
Patterns should always be implemented as placeholders, optionally backed by a mixin.
Modules are a "semantic" and specific assemblage of one or more elements, patterns, or even other modules.
Modules include: page header, navigation, hero
The line between "pattern" and "module" can be blurry and subject to personal interoperation, but I like to think of a module as anything that appears only once on a page (like the page header or footer) and patterns as anything that appears in multiple places.
In practice, when engineering modules, from one to the next, small UI patterns may emerge. If practical, try to encapsulate these smaller patterns for reuse, but don't lose sleep over them.
Elements, patterns, and modules should never assume a particular outer size; they should be engineered to occupy 100% of their containers. Elements within a module can have width in relation to sibling elements, but the module itself should not.
Layouts control sizing and page-specific styles. I like to think of the layout file as the mortar between the bricks of my modules and patterns.
The layout Sass file defines the overall width of the page as well as the widths and relationships of the modules and patterns on the page.
In general a module or pattern should not contain any width styling. This makes the module more portable. A module should be self-contained and not be concerned with where or how it will be used. This allows for flexibility when it comes time to assemble modules/patterns for a given page.
Layouts are an appropriate place to put style overrides for modules that are shared across pages.
Test comment