This article is a quick how-to create a Bootstrap subtheme for Drupal 7, as described here and here, to be able to work with the Sass CSS preprocessor. If you don’t know what Sass is and does, read this introductory guide.

TL;DR: Sass is a CSS3 extension allowing you to use programming ‘techniques’ such as variables, nesting, inheritance and many other useful tricks (see mixins and operators for example) to simplify CSS development. Check it out. To simplify our development work, we will be using the Compass framework and we will also see how to use Grunt task runner for automation.

Allons y! We assume you have installed Drupal 7 and Bootstrap theme in it. Hint: Most compass/grunt commands in this tutorial can also be used for Drupal 8 sub-theme development — you only need to change the first couple of commands (about renaming startekit files and variables), see here.

So, this is the first step: Copy the Sass starterkit folder (called sass) from the sites/all/themes/bootstrap/starterkits folder into sites/all/themes folder.

Rename the sass folder to a unique machine readable name. This will be your sub-theme’s “name”. For this quick tutorial, we assume you renamed it to dreaming.

Change directory into the dreaming subtheme directory.

Rename the file sass.starterkit to match the folder/theme name you have chosen above and append .info (e.g. dreaming.info):

mv sass.starterkit dreaming.info

Open that file (dreaming.info) with your favorite text editor and change the name and description of your theme (and any other properties to suite your needs). Save the file.

Using git, download the latest 3.x.x version of Bootstrap Framework Source Files from here into the your new sub-theme folder:

git clone https://github.com/twbs/bootstrap-sass.git bootstrap

This should create a sub-directory named bootstrap, so you must have a bootstrap directory inside ./subtheme.

Install node.js and ruby in your system (not covered here, sorry!).

Next install Sass compiler and Compass. Note: We are using the Ruby version of Sass, skip to the Grunt section further below to use the more recent Dart version:

gem install sass

gem install compass

To take advantage of all the features of the command compass stats which outputs statistics of Sass stylesheets, install css_parser as well:

gem install css_parser

Now, change directory to one step above your subtheme and write the command (changing `dreaming` to your chosen name):

compass create dreaming

This will create the necessary config files along with a default directory called sass which you can safely delete). Edit the file config.rb and change the default values compass used, i.e. css_dir and sass_dir

css_dir = “css”
sass_dir = “scss”
images_dir = “images”
javascripts_dir = “js”

In that file you may change other configurations such as preferred output style, debugging comments (that display the original location of selectors) etc. I.e. to disable comments in your final css file uncomment the line
#line_comments = false

Save the file. For reference, here’s my config.rb:

require 'compass/import-once/activate'
# Require any additional compass plugins here.
 
# Set this to the root of your project when deployed:
http_path = "/"
css_dir = "css"
sass_dir = "scss"
images_dir = "images"
javascripts_dir = "js"
 
# You can select your preferred output style here (can be overridden via the command line):
output_style = :compressed
 
# To enable relative paths to assets via compass helper functions. Uncomment:
# relative_assets = true
 
# To disable debugging comments that display the original location of your selectors. Uncomment:
line_comments = false

Now run compass from within your subtheme  folder:

compass watch

You should see

>>> Compass is watching for changes. Press Ctrl-C to Stop

This means that compass will monitor sass files in sass_dir for changes and automagically compile them to the final .css  inside css_dir.

So, open up

scss/_default-variables.scss

and change your style by adding some Sassy CSS (that’s what ‘scss’ stands for). I.e. add:

$link-color: #a90909;
$link-hover-color: darken($link-color, 15%);

Remember: SCSS syntax is  like CSS as it was designed to be a superset of CSS3’s syntax. In effect, every valid CSS3 stylesheet is also valid SCSS.

Once you save the file, compass will see the changes and compile the new style.css inside css subfolder. Note: Of course you could compile Sass files by hand using

sass scss/style.scss css/style.css

but you don’t want to do that every time you add/change any style in your SCSS files.

Grunt

Compass is nice, but what if we want to be able to run various tasks automatically while developing our theme? We can use Grunt for this.

First, let’s install Grunt globally:

npm install -g grunt-cli

And locally:

npm install --save-dev grunt

Now, install the Grunt plugins we will use in the Grunt config file (see further below).

To watch your files for changes, install grunt-contrib-watch with this command:
npm install grunt-contrib-watch --save-dev

To compile your Sass files, you have two choices:

a)  grunt-contrib-sass which depends on the deprecated Ruby version of the sass compiler
npm install grunt-contrib-sass --save-dev

In this case also install grunt-contrib-compass to be able to use Compass in Grunt:
npm install grunt-contrib-compass --save-dev 

b) Because the grunt-contrib-sass depends on a deprecated version, you can install grunt-dart-sass instead:

npm install sass grunt-dart-sass --save-dev 

Since grunt-contrib-compass is not compatible with grunt-dart-sass nor grunt-sass, thus you also need to install a compass-importer plugin:

npm install compass-importer --save-dev 

What else we can do with Grunt? For instance minify our javascript files.  To do this we install the grunt-contrib-uglify plugin:
npm install grunt-contrib-uglify --save-dev

To jshint your javascript:
npm install grunt-contrib-jshint --save-dev

To concat the js files:
npm install grunt-contrib-concat --save-dev

To be able to run any (linux) shell command before or after running grunt tasks, install grunt-shell:
npm install grunt-shell --save-dev

All the above in one command:

npm install grunt grunt-contrib-watch sass grunt-dart-sass compass-importer grunt-contrib-uglify grunt-contrib-jshint grunt-contrib-concat grunt-shell --save-dev

Now, to have Grunt monitor your SCSS/JS files and automate your development flow (for example, live-reload your site in your browser (once you’re logged) or clear drupal caches after any css/js change) create a new file called Gruntfile.js with the following code:

// only for option (b)
var compass = require('compass-importer');
 
module.exports = function (grunt) {
    grunt.initConfig({
        watch: {
            src: {
                files: ['**/*.scss', '**/*.php'],
                // if sass option (a), uncomment this
//                tasks: ['compass:dev', 'shell:drush']
                // option b, comment this otherwise
                  tasks: ['dart-css', 'shell:drush']
            },
            scripts: {
                files: ['./js/includes/*.js'],
                tasks: ['jshint', 'concat:js', 'uglify', 'shell:drush'],
                options: {
                    nospawn: true,
                    livereload: 45729
                }
            },
           options: {
                livereload: false,
            },
        },
        // only for option (a) 
//        compass: {
//            dev: {
//                options: {
//                   sassDir: 'scss',
//                    cssDir: 'css',
//                    imagesPath: 'images',
//                    noLineComments: true,
//                    outputStyle: 'compressed'
//                }
//            }
//        },
         // only for option (b)
        'dart-sass': {
            options: {
                noLineComments: true,
                sourceMap: false,
                outputStyle: 'compressed',
                importer: compass
            },
            target: {
                files: {
                    'css/style.css': 'scss/style.scss'
                }
            }
 
        },
        concat: {
            options: {separator: ';'},
            js: {
                src: ['./js/includes/*.js'],
                dest: './js/compiled.js'
            },
        },
        jshint: {
            all: ['js/src/'],
 
            options: {
                    loopfunc: true
            },
        },
       uglify: {
        options: {
          banner: '/*! dimitris kalamaras < %= grunt.template.today("yyyy-mm-dd") %> */\n'
        },
        build: {
          src: './js/compiled.js',
          dest: './js/compiled.min.js'
        }
       },
       shell: {  
          drush: {
             command: 'drush cr'
          }
       }
    });
    // only for option (a) 
    //grunt.loadNpmTasks('grunt-contrib-compass');
    //grunt.loadNpmTasks('grunt-contrib-sass');
    // only for option (b)
    grunt.loadNpmTasks('grunt-dart-sass');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-shell');
};

This configuration sets up a ‘watch’ task which monitors any .scss and .php files as well as any .js files in js/includes folder. It instructs Grunt to execute the tasks compass:dev, shell:drush every time you change your SASS scripts. The former task calls Compass to compile scss to css, while the latter clears drupal’s caches. Also, the config instructs Grunt to run the tasks jshint, concat:js, uglify and shell:drush every time you change any js script inside the folder js/includes. So, if there are scripts in that folder, Grunt will concatenate them and minify them to a single js/compiled.min.js file with an appropriate banner containing a timestamp (feel free to change the ‘banner: bla bla’ option to suite your needs). It’s nice, but if you don’t need that, just remove the relevant options from the Gruntfile.js.

We are ready to use Grunt. Enter:

grunt watch

Now, every time you change any scss, js (or php!) files, Grunt will compile your Sass/SCSS files into a compressed style.css (without comments), will concatenate any js files in js/includes and minify them into a single file called js/compiled.min.js. It will also run the command `drush cr` (drupal 8) after any other task, so you don’t have to do it yourself.

Isn’t that nice or what? Have fun!