How to Customize Twitter Bootstrap’s Design in a Rails app

This entry is part 3 of 3 in the series Twitter Bootstrap and Rails

Twitter Bootstrap and Rails

Maybe customizing Twitter Bootstrap’s designlike this wasn’t such a good idea!

Back in November I discussed various options for integrating Twitter Bootstrap into a Rails 3.1 app, including using the less-rails-bootstrap and bootstrap-sass gems. Then last month I wrote a follow up tutorial showing how to quickly create a working web site using Twitter Bootstrap, Formtastic and Tabulous. Today I’d like to continue this series by discussing how to customize the Twitter Bootstrap design itself.

You might ask: Why customize Twitter Bootstrap at all? After all, their design looks great out of the box – why second guess their design decisions? Well, you might decide you like a certain color or font better, or more likely you want to distinguish your web site from all the other sites that are using Twitter Bootstrap also. It’s so easy to use that many developers have adopted it, and more and more web sites are beginning to have that same look and feel.

Or you might ask the opposite question: Why not just discard Twitter Bootstrap and write your own design that sets your site apart from all the others out there using Twitter Bootstrap? The reason is that Twitter Bootstrap provides a tremendous amount of useful CSS support that would take a long time to reimplement. Just look at all of the features on their home page – discarding all of these just to make your site look a little different would be a mistake.

One interesting option I came across recently is the concept of “Twitter Bootstrap themes,” which will allow you to pick from a series of different designs, while keeping all of the reset, typography, form, table and other styling support. While there are no themes right now, the Paris designer and entrepreneur Sacha Greif is currently working on the first theme to provide an alternative to Twitter’s design, which he calls “Fuzzy.” You can sign up here to have Sacha send you an email when it’s ready.

However, since Twitter Bootstrap themes are still not available, today I’m going to discuss the technical mechanics of how to go about customizing Twitter Bootstrap’s Less and/or Sass code yourself – assuming you are or work with a good designer: Where is the Twitter code? How do I change their font and color settings? How do I make more substantial changes to their design? Read on to learn more…

Customizing Twitter Bootstrap variables with Bootstrap-Sass

Last month I showed how to build a simple Rails 3.1 scaffolding site called “OrigamiHub” that ended up looking like this:

Origami Hub app from last month

To build OrigamiHub I used a Ruby gem called Bootstrap-Sass. I imported the Twitter code into the site by writing a file called app/assets/stylesheets/origami_hub.css.scss containing this code:

@import 'bootstrap';

body {
  padding-top: 60px;
}

Although I didn’t explain it this way last month, this is already the simplest possible example of how to customize the Twitter design: the “padding-top” style overrides or adds to the standard body style Twitter chose. By declaring your styles after the “@import ‘bootstrap’” line, you can override their CSS style code with your own styles. This is easy enough to understand: the browser processes all of the CSS code in the order it receives it; the code received towards the end will override the CSS styles declared earlier. By including your styles second, you can easily override anything Twitter’s CSS code did.

However, the developers behind Twitter Bootstrap anticipated that designers may want to tweak their color, font or layout selections, and created a code file called “variables” containing commonly used global values. Since I used Bootstrap-Sass for OrigamiHub, this file will be called variables.css.scss, and I’ll be able to find it as follows using Bundler:

$ cd `bundle show bootstrap-sass`
$ find vendor/assets/stylesheets
vendor/assets/stylesheets
vendor/assets/stylesheets/bootstrap
vendor/assets/stylesheets/bootstrap/forms.css.scss
vendor/assets/stylesheets/bootstrap/mixins.css.scss
vendor/assets/stylesheets/bootstrap/patterns.css.scss
vendor/assets/stylesheets/bootstrap/reset.css.scss
vendor/assets/stylesheets/bootstrap/scaffolding.css.scss
vendor/assets/stylesheets/bootstrap/tables.css.scss
vendor/assets/stylesheets/bootstrap/type.css.scss
vendor/assets/stylesheets/bootstrap/variables.css.scss
vendor/assets/stylesheets/bootstrap.css.scss

See November’s post for more details. Now let’s take a look at what’s inside variables.css.scss:

/* Variables.less
 * Variables to customize the look and feel of Bootstrap
 * ----------------------------------------------------- */

// Links
$linkColor:         #0069d6 !default;
$linkColorHover:    darken($linkColor, 15) !default;

// Grays
$black:             #000 !default;
$grayDark:          lighten($black, 25%) !default;
$gray:              lighten($black, 50%) !default;
$grayLight:         lighten($black, 75%) !default;

...etc...

It’s not hard to figure out that by changing one of these values we can quickly change the appearance of the web site. However, it’s not a good idea to edit this code directly since it’s located inside the Bootstrap-Sass gem. Instead, as Thomas McDonald shows on the Bootstrap-Sass Readme page, you can change one of these values by specifying the value you want BEFORE you import bootstrap, like this:

$linkColor: #FF69d6;

@import 'bootstrap';

body {
  padding-top: 60px;
}

Now reloading the page I get a pink “back” link instead:

Pink Back Link

If this doesn’t work for you, be sure you have the latest version of Bootstrap-Sass, at least v1.4.1 or later:

$ bundle update bootstrap-sass

It turns out there’s a subtle but important detail in the variables.css.scss file above – the odd use of “!default” at the end of each variable declaration:

$linkColor:         #0069d6 !default;

Here “!default” is a Sass language feature that means: if there was already a value declared for this variable (“linkColor” in this example) then leave that unchanged and use it. If not, then use the specified value by default (“#0069d6” here). Practically speaking this means that you need to be sure to declare custom variable settings before and not after the “import bootstrap” line. This use of “!default” was added very recently to Bootstrap-Sass, so be sure to update the gem before trying to change a setting from variables.css.scss.

Customizing Twitter Bootstrap variables with Less-Rails-Bootstrap

As I explained back in November, another option for including Twitter Bootstrap into a Rails app is to use the Less language instead of Sass, using the Less-Rails-Bootstrap gem. While not included in a Rails app by default like Sass, Less can be a good choice since it’s the language originally used by Twitter to developer Twitter Bootstrap.

If I had used Less-Rails-Bootstrap to build OrigamiHub, I would have a file called origami_hub.css.less instead, with very similar code:

@import 'twitter/bootstrap';

body {
  padding-top: 60px;
}

The only difference here is that the “import” command contains a different path to the Less code, since Less-Rails-Bootstrap uses a slightly different directory structure:

$ cd `bundle show less-rails-bootstrap`
$ find vendor/assets/stylesheets
vendor/assets/stylesheets
vendor/assets/stylesheets/twitter
vendor/assets/stylesheets/twitter/bootstrap.css.less

You can see only the top-level bootstrap.css.less file is located under vendor/assets/stylesheets. The other Less code files are here:

$ find vendor/frameworks
vendor/frameworks
vendor/frameworks/twitter
vendor/frameworks/twitter/bootstrap
vendor/frameworks/twitter/bootstrap/bootstrap.less
vendor/frameworks/twitter/bootstrap/forms.less
vendor/frameworks/twitter/bootstrap/mixins.less
vendor/frameworks/twitter/bootstrap/patterns.less
vendor/frameworks/twitter/bootstrap/reset.less
vendor/frameworks/twitter/bootstrap/scaffolding.less
vendor/frameworks/twitter/bootstrap/tables.less
vendor/frameworks/twitter/bootstrap/type.less
vendor/frameworks/twitter/bootstrap/variables.less
vendor/frameworks/twitter/bootstrap.less

Here we can see all the same code files, but using the “less” file extension instead. And you’ll find the same set of variables and values in variables.less that we saw above in variables.css.scss:

// Links
@linkColor:         #0069d6;
@linkColorHover:    darken(@linkColor, 15);

// Grays
@black:             #000;
@grayDark:          lighten(@black, 25%);
@gray:              lighten(@black, 50%);
@grayLight:         lighten(@black, 75%);

...etc...

Less uses a slightly different syntax than Sass: “@linkColor” instead of “$linkColor”. Also we don’t see the “!default” directive we had earlier. Most importantly, changing the value of a variable in Less works differently than it does in Sass; there’s no concept of a default value and overriding it. In fact, in Less variables are actually implemented as constants. See lesscss.org for more details. This means once you define a value for a variable it cannot be changed.

At first glance, this might mean that the only way to change the Twitter Bootstrap settings would be to edit the Twitter Less code directly, right inside of Less-Rails-Bootstrap. But this would be very ugly: every time I updated Less-Rails-Bootstrap I would lose my changes. While it might be possible to track my changes in a branch using git somehow, re-merging every time I got a newer version, this would be an obvious maintenance problem and an ongoing headache.

Actually, it turns out there’s a simpler way to do it. Because of a bug in the Less compiler, you can override the “constant” value of a variable by changing it after it is initially declared. That is, the value of the variable constant will be whatever its last assigned value is. It seems that the Less compiler first evaluates the values of all constants, and then evaluates the rest of the Less script, substituting the value for each variable.

What this means for customizing Less-Rails-Bootstrap is that you need to declare your custom variable values AFTER the import line, not before it like with Bootstrap-Sass. Here’s an example changing the gray scale colors to use a shade of red:

@import 'twitter/bootstrap';

body {
  padding-top: 60px;
}

@black: #200;

“#200” refers to a color that is not quite black, but has some red in it; remember “RGB” = “Red-Green-Blue.” Now my site looks like this:

@black variable changed to be red

Variables aren’t enough!

Sadly, there just aren’t enough customizable settings in the variables.less file – aside from linkColor, the only other settings there have to do with font size, colors and grid sizes. And as you can see from the screen shot above, the color settings don’t actually even work properly, since many of the Twitter Less code files refer to hard coded color values directly: here the navigation bar is still black even though I’ve changed the value of “black” to be more red. Also, it’s very odd to change the value of the “black” variable to be a shade of red in the first place… very confusing!

Unfortunately, the only good way to customize the Twitter Bootstrap design is to look closely at the HTML you are using in your site, find where the styles you are actually using are defined, and then override the Sass or Less code as needed.

Let’s take an example: suppose my designer or I decided to make the “Create Origami” button a shade of red, instead of blue. The only effective way to do this would be to first use the Chrome “Inspect Element” command (or a similar command from your favorite browser) like this:

Chrome Inspect->Element right click menu item

… and then find the element’s CSS style:

Finding a style in the Chrome developer tools window

Here I can see that the button’s blue background color is set by the “btn.primary” class. Searching through the Less code inside of Less-Rails-Bootstrap for this definition:

$ cd `bundle show less-rails-bootstrap`
$ cd vendor/frameworks/twitter/bootstrap
$ ack btn
patterns.less
512:.btn,
545:// Base .btn styles
546:.btn {
619::root .btn {
624:button.btn,
625:input[type=submit].btn {
697:  .btn {
871:  .btn {

… I can see that the button related styles are defined in patterns.less. Looking through the file, I find the primary button style code:

// Base .btn styles
.btn {
  // Button Base
  cursor: pointer;
  display: inline-block;

... etc ...

  // Primary Button Type
  &.primary {
    color: @white;
    .gradientBar(@blue, @blueDark)
  }

... etc...

}

Here you can see how the primary button is defined: using a white font color and a gradient blue background (“blue” –> “blueDark”). And you can also see the blue value is hard coded into the patterns.less file – there’s no variable in variables.less called “$primaryButtonColor” or something similar, although there is a comment indicating this variable might be added soon.

To change the form buttons to be red instead, we need to copy/paste this Less code out into our application’s Less file (origami_hub.css.less) and make the desired changes:

@import 'twitter/bootstrap';

body {
  padding-top: 60px;
}

// Custom colors:
@black:   #200;
@redDark: darken(@red, 5);
@linkColor: @redDark;
@titleColor: lighten(@red, 10);

// Copied from vendor/frameworks/twitter/bootstrap/patterns.less in less-rails-bootstrap
.btn {

  // Primary Button Type
  &.primary {
    color: @white;
    .gradientBar(@red, @redDark)
  }
}

.topbar {
  // Hover and active states
  ul .active > a {
    color: @titleColor;
  }

  a {
    color: @titleColor;
  }

  // Website name
  .brand {
    color: @titleColor;
  }
}

Here I’ve defined a couple of new shades of red, and used them to override a few other style definitions related to the navigation bar text, along with the primary button style, leading to a more red version of my site:

OrigamiHub with a customized version of the Twitter Bootstrap design

Conclusion

This seems like a lot of work to change something from blue to red! Why bother? Or why not just discard Twitter Bootstrap entirely and start from scratch?

The reason is obvious: if you browse for a few minutes around the Twitter Bootstrap Less or Sass code files in one of the gems I’ve mentioned here, you’ll see a tremendous number of useful styles and features. Here are just a few examples:

  • reset.less – contains the reset styles to create a clean, cross-browser foundation to use, based on Eric Meyer’s work from 2007.
  • mixins.less – contains a series of useful functions that can be reused by other styles.
  • type.less – useful typography utilities.
  • etc…, etc…

And that’s just the beginning; there are a number of Twitter Bootstrap features I haven’t even mentioned here. Plus a newer version of Twitter Bootstrap, v2.0, is underway and will soon add even more Less/Sass code files and CSS features to the list.

The way I like to think about Twitter Bootstrap is that it’s a CSS coding platform. The same way that Rails makes it a lot easier to build a web site by implementing commonly needed functionality that all web sites need, Twitter Bootstrap, on a much smaller scale, implements many of the style features that any web site would need. The problem is that to use it effectively you really do need to take the time to learn how the Less, or translated Sass, code works, since there are many hard coded design details. To use it with a custom, unique design that you or a designer you are working with has written will require you to manually copy, paste and customize the portions of Twitter Bootstrap you want to change. Hopefully this process will become easier in future versions, as they add more variables and other ways to customize their design!

Twitter Bootstrap and Rails

<< Too good to be true! Twitter Bootstrap meets Formtastic and Tabulous

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://builtwithbootstrap.tumblr.com/ Simon Hamp

    Great tutorial, Pat! Just want to let you and others know that anything they build that uses even parts of Bootstrap can get a slot on Built With Bootstrap (http://builtwithbootstrap.tumblr.com/), our little showcase. Just submit a short, descriptive post with a screenshot :)

    • http://patshaughnessy.net Pat Shaughnessy

      Cool idea Simon! I already told one of my developer friends to submit his site there :)

  • http://oscarvillareeal.com Oscar

    Awesome post pat! Ive been playing a bit with bootstrap and I can see why developers are loving it. Will have to apply your less tutorial on it. Thanks!

  • http://47hats.com Bob Walsh

    Fantastic series of well-writtern articles, but now I have to choose:

    With Twitter-bootstrap 2.0 out in a week, if you were starting a Rails 3.2 project today, would you a) less-rails-bootstrap or b) the bootstrap-sass gem by Thomas McDonald?

    • http://patshaughnessy.net Pat Shaughnessy

      Hi Bob, Thanks!

      First of all, I’m not sure either of those two gems have been updated with TB 2.0 yet – although I expect both of them would be rapidly once the new version of bootstrap is released.

      If you have a preference for Less vs. Sass, then choose based on that. TB was originally written in Less, but I also trust that Thomas will translate it to Sass properly.

      Finally if you have no other reason to choose one way or the other, I might go with bootstrap-sass just because Rails already supports Sass (.scss files) by default in the asset pipeline, while it does not support Less. I assume that’s still true in Rails 3.2.

      But really they are both excellent gems and either will do the job for you.

  • angelo

    Wow, Pat… This article series is amazing! I’m new to Bootstrap (I was introduced to it by Ryan’s awesome Railscasts site,) and after a long internal battle of whether to use Bootstrap vs. Bourbon vs. Compass, within minutes, I’m up and running and productive. I swapped out Formtastic with Simple Form and couldn’t be happier.

    I can honestly say that for the first time, I am excited about the UI ‘design’ side of web development… I hope deploying is as easy as getting up and running in development!

    I owe you a beer (or 5) if you ever make it out to Connecticut.

    • http://patshaughnessy.net Pat Shaughnessy

      Ha ha thanks – I’ll have to take you up on that offer someday :)

  • Jesus Garza

    Have you tried stylebootstrap.info?

  • Dixon

    This is very helpful, thanks very much.

    With the appearance of “theme” sites like http://bootswatch.com, can you revisit the idea of how to set up a theme in Rails? I’m learning Rails and I wonder what is the best practice to do this, as there are so many places you can drop the theme stuff.

    For the record, I’m trying to install the United theme.

  • http://www.hillarykeel.com Lori

    What would the command be to move Twitter-Bootstrap-sass from gitkeep into my vendor assets folder or assets/stylesheets folder so that I can trim it down and customize it for a Ruby on Rails website that is already live? What files would need changing? Thanks