A starting point for a scalable, maintainable CSS architecture.
- Compass with vertical rhythm
- SMACSS modules with BEM syntax for modifiers & subcomponents
- A Susy mobile-first responsive grid module
- Normalize.css
- Standalone IE7, 8 & 9 stylesheets
"But I hate Compass! Grrrr!"Settle petal. Just replace replace Compass & Susy with [Bourbon](http://bourbon.io/) & [Neat](http://neat.bourbon.io/) or your own alternatives and you'll be fine.
I wrote a blog post explaining how we use this approach on the Envato marketplaces.
Assuming you have your own plans for asset compilation, you'll probably just want to drop the stylesheets
folder into your usual stylesheets path (note the dependencies in the Gemfile
and Compass configuration in config.rb
).
That said, you can run this as a standalone Compass project if you wish.
bundle install
compass watch
orcompass compile
to compile CSS tocss/
With the exception of base element styles & global state classes, everything is a standalone, reusable module that doesn't change regardless of the context it appears in.
Grid classes and "unique" things like your site header & footer aren't special. IDs aren't welcome. Everything - everything - is a module.
Here's what a simple module, /stylesheets/modules/_simple_widget.sass
, might look like:
.simple-widget
color: goldenrod
Here's a slightly more complex module, /stylesheets/modules/_fancy_widget.sass
:
// The canonical fancy-widget class
.fancy-widget
color: fuchsia
// A modified fancy-widget
.fancy-widget--important
@extend .fancy-widget
font-weight: bold
// Hey look, module-specific states are just modifiers too!
// The "is" keyword indicates that this is a state class.
.fancy-widget--is-loading
background: url(spinner.gif)
// It's up to you whether you add a state class on top of the module class...
// <b class="fancy-widget fancy-widget--is-loading">
// or @extend the original so you can replace it...
// <b class="fancy-widget--is-loading">
//
// I usually end up with a combination of both.
// Sometimes it's easier to update a single state attribute with JS instead of
// faffing about with adding & removing state classes. That's ok.
.fancy-widget[data-state=is-loading]
background: url(spinner.gif)
// A subcomponent (some component that must be a child of .fancy-widget)
// Generally subcomponent classes exist purely to position an element inside the module.
// Whatever is inside a subcomponent can usually be extracted out into its own module.
.fancy-widget__close-button
margin-left: 20px
Breakpoint-specific styles are kept right inside their module via Susy's at-breakpoint
mixin.
.my-module
color: floralwhite
+at-breakpoint($tablet)
color: plum
+at-breakpoint($desktop)
color: burlywood
Like breakpoint-specific styles, IE-specific styles are kept with the selector they belong to, but are only output in a seperate application-ie7.css
(or 8, or 9) stylesheet that is included with conditional comments (hat tip).
.my-module
color: olive
@if $lt-ie9
position: relative
@if $ie7
zoom: 1
@if $ie8
color: lime
@if $ie9
color: cadetblue
In IE7 and 8, at-breakpoint($tablet)
& at-breakpoint($desktop)
blocks are scoped to a .lt-ie9
class instead of being scoped to media queries. All other breakpoints (eg $tablet-max
) are discarded.
Ideas borrowed from many places, including:
- SMACSS by Jonathan Snook
- Clean out your Sass junk drawer by Dale Sand
- About HTML semantics and front-end architecture by Nicolas Gallagher
- MindBEMding - getting your head 'round BEM syntax by Harry Roberts
- IE-friendly mobile-first CSS with Sass 3.2 by Jake Archibald
- Organising SASS Assets in Rails by Ben Taylor
Style is released under the MIT License