Using and Migrating to Bootstrap 4 on Rails

Matthew Beale
201 Created
Published in
5 min readJan 26, 2018

--

Recently the web development world welcomed the release of Bootstrap 4 stable:

Bootstrap is a web style framework, and I’ve been really happy with the improvements Bootstrap 4 makes. Like version 3, this new release looks great out of the box. To improve on this baseline, it provides an excellent interface to your application via SASS and offers configuration of its baseline styles.

Organizing your app

We’ve successfully used a layout like the following for both Ember projects and, here as an example, Rails projects:

app/
assets/
stylesheets/
components/
This directory contains re-usable UI components. For example
a dropdown you use throughout the site. A good rule of thumb
here is that components are parts of the UI you could
imagine using on another website.
pages/ Files in this directory are named to match up with routes or
controllers. They are to be used sparingly, and they are
basically special case styles for some arbitrary page. A
good rule of thumb for adding something to pages/ is that
you can never imagine using it on any other pages in the
app.
themes/ Many of our styles end up here. These files should contain
styles specific to this application, but generally useful
and re-used across the site.
utils/ This directory is also used sparingly: It contains mixins or
SASS functions used elsewhere.
_bootstrap-config.scss - Configuration of Bootstrap's baseline
_bootstrap-custom.scss - Which parts of Bootstrap to include
_colors.scss - Our color palette
_config.scss - Configuration variables for app styles
_fonts.scss - Font list for the app
application.scss - Include the various files here

application.scss then ends up looking something like:

@import 'fonts';
@import 'colors';
@import 'bootstrap-config';
@import 'bootstrap-custom';
@import 'config';
@import 'utils/**/*';
@import 'components/**/*';
@import 'themes/**/*';
@import 'pages/**/*';

Bootstrap 4 is configurable

In _bootstrap-custom.scss you import the parts of Bootstrap you want to use. Since some of these imports add CSS output, you want an opt-in policy here.

Bootstraps’s documentation on importing covers some of this, but you’ll want to always include functions, variables, and mixins. The other imports are optional, and I often use the Bootstrap source for an authoritative list of what is available.

In _bootstrap-config.scss you can override the Bootstrap defaults. The Bootstrap documentation on variable defaults is a good place to look for more information, and again if you want an exhaustive list of options I suggest going to the source code. As an example, this is where you would set a default font size or link color.

Bootstrap 4 has a very powerful system for colors. It leverages SCSS functions to maintain a map of colors or to provide color variants. I’ve not used this system extensively yet, but the ability to use these maps to generate style modifiers seems tremendously useful, especially in conjunction with BEM style naming, which is a convention I suggest you adopt regardless of what tools you use to generate CSS.

Bootstrap 4 helps your class names remain semantic

One thing I love about the latest release of Bootstrap is its collection of useful SASS functions. These give you all the flexibility of the classic col-12.col-sm-12 class names without sacrificing the abstraction of a class with a semantic name.

For example, I’ve often written the following HTML in an app:

<div class="row">
<div class="col col-md-10 col-lg-6">

Which would describe a row and a div that defaults to 12 columns wide, at the medium breakpoint is only 10 columns, and at the large breakpoint is 6 columns.

While prototyping this API is pretty great, once an app is mature and pages become re-iterations of existing styles you’ll see a lot of copy-paste. It becomes impossible to apply a unified style change across the site.

Bootstrap 4’s breakpoint and grid functions offer a huge improvement. Instead of the above non-semantic classes, you can write HTML like this:

<div class="dashboard-pane--wrapper">
<div class="dashboard-pane--content">

And SCSS like the following:

/* app/assets/stylesheets/themes/dashboard.scss */
.dashboard-pane {
&--wrapper {
@include make-row();
}
&--content {
@include make-col-ready();
@include media-breakpoint-up(md) {
@include make-col(10);
}
@include media-breakpoint-up(lg) {
@include make-col(6);
}
}
}

This flexibility to use SCSS functions where you once used to use non-semantic classes exists across much of the new Bootstrap 4 API.

Migrating a Rails project from Bootstrap 3 to Bootstrap 4

Recently I worked with a client using Bootstrap 3. We chose to migrate to Bootstrap 4, but we didn’t want to bring the old non-semantic class names and legacy CSS with us.

Do accomplish the migration we took several steps:

  1. We forked the Bootstrap 3 bootstrap-sass gem and re-released it as bootstrap-3-sass (https://github.com/kpfefferle/bootstrap-3-sass). In our fork, we renamed all files, directories, and classes from bootstrap to boostrap-3. This allowed us to add a dependency on the Bootstrap 4bootstrap-rubygem library (https://github.com/twbs/bootstrap-rubygem) and not have a conflict between any @import names. Although you wouldn’t want to to import both versions of Bootstrap SASS in the same application file, with this change it is possible.
  2. We moved the legacy files into a directory and renamed them with -legacy postfixes. We changed any import from bootstrap in those files over to bootstrap-3.
  3. We added the legacy stylesheet path to Rails.application.config.assets.precompile in the config/initializers/assets.rb file. See the Rails docs on precompiling for more details.
  4. In the app/views/layouts/application.html.erb file we added a check to use an alternative stylesheet tag if it was configured with content_for. This allows us to migrate individual pages.

For example our application.html.erb looks like:

<% if content_for?(:head_style_tags) %>
<%= yield :head_style_tags %>
<% else %>
<%= stylesheet_link_tag 'application-legacy', media: 'all' %>
<% end %>

And at the top of every converted view we add:

<% content_for :head_style_tags do %>
<%= stylesheet_link_tag 'application', media: 'all' %>
<% end %>

Which is our opt-in to the new styles. Eventually, we can swap the default and remove those opt-in lines.

Common HTML between the two stylesheets still exists in the application layout, for example much of the site’s navigation. Making that markup work identically in old and new SCSS was challenging, however our goal was that the remainder of the website (which is much larger and complex) can be migrated incrementally. We’re happy and very productive with this approach.

If you’ve not investigated Bootstrap 4 or kept up with the growing number of interesting SASS function-based style frameworks, I encourage you to take a look and see how they can improve your styling!

At 201 Created we’ve helped dozens of clients (including YC startups and Fortune 50 companies) make the most of open source solutions like Bootstrap. Contact us to learn more about our work and how we can make your team more effective.

--

--

JavaScript consulting through 201-created.com. Coding mostly Ember, eating mostly veggies. Ember.js Core Team.