A SASS with Bootstrap Workflow

May 14, 2013 Ward Penney

So you’ve decided to start a project with Twitter Bootstrap, but you want to use SASS (SCSS)? Well, this is the post for you. Here are some tips from my current workflow for starting a SASS with Bootstrap project. DISCLAIMER: there many ways to slice this cake. So please, take what you like and leave what you don’t!

A Typical File Structure

In the stylesheets source folder, I generally only have one primary SASS file, that imports all others. If you are using a Rack app, do not use sprockets directives here, just SASS.

Depending on your stack, you will have some place where you have a stylesheets/ folder. Within that folder, I typically set up a basic folder structure that looks like this:

  • application.sass
    • /libraries
      • _variables.sass
      • _mixins.sass
    • /vendor
      • _bootstrap.scss
      • _bootstrap-responsive.scss
      • bootstrap/
        • _accordion.scss
        • _alerts.sass
        • _breadcrumbs.sass
        • etc…
    • /components
      • _tables.sass
      • _forms.sass
      • etc…
    • /sections
      • _homepage.sass
      • _product_detail.sass
      • _style_guide.sass
      • etc…

./libraries/: contains only variables and mixins: SASS that does not render any actual CSS, but is used later. Why? You’ll find out later!

./vendor/: Vendor framework libraries. In this case, only Bootstrap is here.

./components/: SASS patterns intended to be used across the site. Pretty much everything in here will be devoted a section in the live style guide.

./sections/: Layouts and other page-specific stylings. Anything that is not intended to be used in multiple places in a versatile way.

Bootstrap Source

I like the Bootstrap source SASS not hidden in a gem because I can want to control exactly which features are included. You don’t want to be in a situation where it feels like you can’t deprecate or evolve away from Bootstrap because you don’t control it. So, here is what I do:

  1. Go to Thomas MacDonald’s amazingly well-maintained Bootstrap port to SCSS at https://github.com/thomas-mcdonald/bootstrap-sass

  2. Copy the contents of https://github.com/thomas-mcdonald/bootstrap-sass/tree/master/vendor/assets/stylesheets to your vendor folder described above

  3. EDIT: You have to do one fix to the files here. Copy the vendor/bootstrap/bootstrap.scss file up one level, and overwrite the vendor/bootstrap.scss file there. Do the same for bootstrap_responsive.scss
  4. Open up the vendor/bootstrap/bootstrap.scss and comment out NEARLY EVERYTHING. Even the grid if you want to use a different grid. Uncomment features as you need them, when your user stories demand the functionality.

  5. Include the vendor/bootstrap file in your ./application.sass file, and BOOM you’ve got a full controllable Bootstrap source.

  6. When you need buttons, uncomment buttons. When you need wells, uncomment wells. Rinse and repeat.

  7. Replicate this process for the javascript also, only including what you need when you need it.

(Note, this method also works if you don’t have Rails, or a rack app that can use gems, this still works for you. Yes, you can compile SASS with Bower and Grunt. Check out Sam Richard’s style guide prototyping stack)

Extending the Grid

With Bootstrap, you may typically insert its class selectors and elements into your markup to compose the, but some peepz do not desire this for semantic, SEO and other reasons.

SASS offers an attractive way to remove the clutter with the SASS @extend directive, however it has two performance pitfalls:

  • In Development: Using it in SASS nesting (more than two levels) may significantly slow down your compilation time, especially if that element is being @extend-ed a lot.
  • In Production, overuse can can create so many selectors on one element that it can lag the browser significantly.

In Bootstrap in particular, it becomes tricky because you have to extend the grid class, as well as the wildcard class that applies the padding. For example, a Bootstrap element classed with .span3 will receive stylings from the .span3 selector, as well as a funky selector [class*=’span’]. For example, you can’t just do this:


.advertising-sponsor
  @extend .span3

This misses the [class*=’span’] wildcard selector because @extend only scours literal selectors, not searching for anything that MAY apply. Therefore, you have to do this:


.advertising-sponsor
  @extend .span3
  @extend [class*='span']

The downside is the second @extend adds an extension to that target selector every time you use it, and a really long one if it is nested. Those hit the performance issues I described above, hard.

So, my process now is to create my own mixin that allows me to quickly pseudo-extend the grid class by calling the Bootstrap mixin that prints their styling. I place the following into my ./variables/_mixins.sass:

=bs-extend-span($spanNum)
  +grid-core-span($spanNum, $gridColumnWidth, $gridGutterWidth)
  float: left
  min-height: 1px
  margin-left: $gridGutterWidth

This essentially renders what bootstrap does for it’s span classes. This does duplicate CSS in the compiled result, but I have found that the performance impact of downloading more CSS pales in comparison to the pains suffered by @extend in development time, or in a more severe case, crashing or lagging the users’ browser.

Styling Bootstrap with Variables

Take a look at the ./vendor/bootstrap/_variables.sass. Notice how all the variables have !default after them? That means that SASS will NOT overwrite this variable if it is already defined. This allows you to create your own ./libraries/_variables.sass file, and include it in the load order before Bootstrap and effectively control those variables. This will be your primary way to style Bootstrap colors and such.

Using Compass or Bourbon with Bootstrap

Some people prefer Compass’ mixins. Some people like Bootstrap’s. Some like Bourbon’s. IMO, they are all good and I don’t mind using any, but it is a good idea to commit to one. For example, Bootstrap’s =Opacity() mixin takes a value from 0-100, while Compass’ function takes a value from 0-1. There is a variable order conflict with =transition(). I sometimes import pieces of compass, instead of the whole thing. For example, I like the ever-handy Compass =experimental() function. You can choose to import only specific files from Compass:

@import compass/css3/shared

Conclusion and Upcoming Topics

That’s it for now! Let me know if you have any topics you want me to expand on, or ideas for posts you want to see. I am currently doing a style guide using Groundwork-CSS, and hope to do a similar post later! Follow me on twitter for various nonsensical ramblings.

 

About the Author

Biography

Previous
On asking for help
On asking for help

Years ago in college, I took part in “The Game”: a 24-long scavenger hunt, driving all over the Bay Area, d...

Next
What in-house design taught me about consulting  (Part 1)
What in-house design taught me about consulting (Part 1)

In the design world, a river runs between the consultants and in-house designers. I’ve worked at big start-...

×

Subscribe to our Newsletter

!
Thank you!
Error - something went wrong!