Customizing Bootstrap (Sass) using Grunt
Update 2015-12-02: I updated the post to use npm instead of Bower to install Bootstrap because it eliminates an extra tool and I hear this is the preferred method.
Update 2015-02-22: My co-workers informed me that Grunt is so last year and Gulp is the new hotness. You wish this post covered Gulp, but instead it covers Grunt.
I recently converted this blog to use Twitter's Bootstrap CSS framework to make it responsive. (In particular, I wanted to read it on my phone.) I was using Blueprint CSS from 2008 so it was about time for an update. Unfortunately my design is also from 2008 but I won't update that. (Web design is hard.)
My problem was that 2014 Bootstrap's 200px gutter width didn't match my 2008 design's 2px gutter. So I wanted to customize the gutter width.
There are a few ways to customize Bootstrap. One option is creating a custom version on Bootstrap's website and downloading it for use on your site. However this doesn't allow you to change things quickly as you develop. Another option is overriding Bootstrap's style in your site stylesheet. However, it's hacky to write compilcated selectors to override something in multiple places when it is set in a single variable in Bootstrap. For example, to change the gutter width, here is the single variable that needs to be changed.
Approach¶
Here is the approach I took to customize Bootstrap. I'm running Ubuntu 14.10 Utopic Unicorn 64-bit.
- Install the Sass version of Bootstrap using npm. The standard Bootstrap project uses Less but my limited knowledge of frontend technology tells me Sass (specifically SCSS) is a better choice. I previously used Bower to install Bootstrap, but I learned that npm can now be used instead of Bower in most cases.
- Override Bootstrap's Sass variables, remove unneeded components, and combine Bootstrap with my site's stylesheet using Sass
@imports
. - Compile the Sass SCSS files to CSS using Grunt and grunt-contrib-sass.
- Commit the compiled Sass files to git. An alternative is to compile the files as part of the deploy process. At work, it is a pain keeping these files in git because there are many merge conflicts and differences in build tool versions and platforms between developers. For my blog, I am the only committer so I won't run into this.
Project directory structure¶
Here is what my project directory structure looks like:
my-project ├── Gruntfile.js ├── node_modules │ ├── bootstrap-sass │ ├── grunt │ ├── grunt-contrib-sass │ └── grunt-contrib-watch ├── package.json ├── sass │ ├── _bootstrap-variables-override.scss │ ├── _bootstrap.scss │ └── mystyle.scss └── static └── css └── mystyle.css
Install Sass¶
Sass is installed using RubyGems, the Ruby package manager.
$ sudo apt-get install ruby
$ sudo gem install sass
$ sass --version
Sass 3.4.13 (Selective Steve)
Install grunt-cli¶
Grunt depends on npm, the Node.js package manager.
$ sudo add-apt-repository ppa:chris-lea/node.js
$ sudo apt-get update
$ sudo apt-get install nodejs
$ npm --version
1.4.28
$ sudo npm install -g grunt-cli
$ grunt --version
grunt-cli v0.1.13
Install bootstrap-sass with npm¶
bootstrap-sass is the official Sass port of Bootstrap. I created this package.json file, /tmp/my-project/package.json
. For more information about the package.json file, see the npm documentation.
{
"name": "my-project",
"version": "0.1.0",
"dependencies": {
"bootstrap-sass": "3.3.1"
}
}
Then I ran npm install
to download the files. The packages are stored in the node_modules
directory.
$ cd /tmp/my-project
$ npm install
Customize Boostrap¶
To customize Boostrap, I copied the node_modules/bootstrap-sass/assets/stylesheets/boostrap.scss
file to my sass
directory, removed the components that I didn't need, and added a line for my custom variable overrides. Here is my final file, named /tmp/my-project/sass/_bootstrap.scss
:
// Variable overrides come first (without !default). Bootstrap default variables
// come second because they use !default (they won't get set if set already) and
// some of them depend on our overrides.
@import "bootstrap-variables-override";
// Core variables and mixins
@import "bootstrap/variables";
@import "bootstrap/mixins";
// Reset and dependencies
@import "bootstrap/normalize";
@import "bootstrap/print";
@import "bootstrap/glyphicons";
// Core CSS
@import "bootstrap/scaffolding";
@import "bootstrap/type";
@import "bootstrap/code";
@import "bootstrap/grid";
@import "bootstrap/tables";
@import "bootstrap/forms";
@import "bootstrap/buttons";
// // I am not using these components so I commented them out to make the CSS file smaller
// // Components
// @import "bootstrap/component-animations";
// @import "bootstrap/dropdowns";
// @import "bootstrap/button-groups";
// @import "bootstrap/input-groups";
// @import "bootstrap/navs";
// @import "bootstrap/navbar";
// @import "bootstrap/breadcrumbs";
// @import "bootstrap/pagination";
// @import "bootstrap/pager";
// @import "bootstrap/labels";
// @import "bootstrap/badges";
// @import "bootstrap/jumbotron";
// @import "bootstrap/thumbnails";
// @import "bootstrap/alerts";
// @import "bootstrap/progress-bars";
// @import "bootstrap/media";
// @import "bootstrap/list-group";
// @import "bootstrap/panels";
// @import "bootstrap/responsive-embed";
// @import "bootstrap/wells";
// @import "bootstrap/close";
// // Components w/ JavaScript
// @import "bootstrap/modals";
// @import "bootstrap/tooltip";
// @import "bootstrap/popovers";
// @import "bootstrap/carousel";
// Utility classes
@import "bootstrap/utilities";
@import "bootstrap/responsive-utilities";
The Boostrap variables are located in node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss
I copied the ones that I was interested in into a _bootstrap-variables-override.scss
file. Be sure to remove the !default
flag and import this file before the default bootstrap variables. For more information about !default
, see the Sass documentation. Here is my /tmp/my-project/sass/_bootstrap-variables-override.scss
file:
// overrides here (do not use !default here)
$grid-gutter-width: 10px;
$font-size-base: 16px;
$headings-font-weight: 800;
In my site stylesheet, I import _bootstrap.scss
. Here is my /tmp/my-project/sass/mystyle.scss
file:
@import "bootstrap";
/* add site style here */
Install grunt plugins¶
To compile the Sass files to CSS, I am using grunt-contrib-sass. I added a devDependencies
section to my package.json file which contains grunt and two grunt plugins. Here is my /tmp/my-project/package.json
. For more information about installing plugins, see the Grunt documentation.
{
"name": "my-project",
"version": "0.1.0",
"dependencies": {
"bootstrap-sass": "3.3.1"
},
"devDependencies": {
"grunt": "0.4.5",
"grunt-contrib-sass": "0.8.1",
"grunt-contrib-watch": "0.6.1"
}
}
I ran npm install
again to install grunt, grunt-contrib-sass, and grunt-contrib-watch.
$ cd /tmp/my-project
$ npm install
Create Gruntfile.js¶
My Gruntfile.js uses the grunt-contrib-sass plugin to compile the Sass to CSS. My input file is sass/mystyle.scss
and my output file is static/css/mystyle.css
. I set the loadPath
so that Sass can find the Bootstrap SCSS files in the node_modules directory to import. Alternatively, I could specify the full path to import in /tmp/my-project/sass/_bootstrap.scss
. For example: @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/variables";
I am also using the grunt-contrib-watch plugin during development to automatically run the compilation whenever a SCSS file changes. For more information on configuring tasks, see the Grunt documentation. Here is my Gruntfile, /tmp/my-project/Gruntfile.js
:
module.exports = function(grunt) {
grunt.initConfig({
sass: {
// this is the "dev" Sass config used with "grunt watch" command
dev: {
options: {
style: 'expanded',
// tell Sass to look in the Bootstrap stylesheets directory when compiling
loadPath: 'node_modules/bootstrap-sass/assets/stylesheets'
},
files: {
// the first path is the output and the second is the input
'static/css/mystyle.css': 'sass/mystyle.scss'
}
},
// this is the "production" Sass config used with the "grunt buildcss" command
dist: {
options: {
style: 'compressed',
loadPath: 'node_modules/bootstrap-sass/assets/stylesheets'
},
files: {
'static/css/mystyle.css': 'sass/mystyle.scss'
}
}
},
// configure the "grunt watch" task
watch: {
sass: {
files: 'sass/*.scss',
tasks: ['sass:dev']
}
}
});
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
// "grunt buildcss" is the same as running "grunt sass:dist".
// if I had other tasks, I could add them to this array.
grunt.registerTask('buildcss', ['sass:dist']);
};
Run grunt¶
To compile the Sass to CSS for production, I run grunt buildcss
. This creates the output CSS file /tmp/my-project/static/css/mystyle.css
.
$ cd /tmp/my-project
$ grunt buildcss
During development, I use grunt watch
to build whenever a SCSS (Sass) file changes.
$ cd /tmp/my-project
$ grunt watch
Other Notes¶
- I don't commit the
node_modules
directory to git. Sass uses the Bootstrap files in node_modules to create the final CSS file. - To configure Bootstrap's Javascript and glyphicons in your project, you can use grunt-contrib-concat and grunt-contrib-copy as spacepope nancho described in his comment.
See Also / References¶
Related posts
- How to use ast-grep with GraphQL — posted 2024-09-24
- Next.js App Router (RSC) projects w/ open source code — posted 2024-07-30
- Next.js Relay GraphQL Pokemon example — posted 2024-05-22
- Example Node.js Passport.js SAML app using OneLogin — posted 2024-05-10
- Aphrodite to CSS Modules codemod — posted 2022-12-09
- Simple codemod example with jscodeshift — posted 2021-05-03
Comments
Hi! Thanks for the article. It helped me a lot.
I have an issue adding javascript to the project. Generally, don't really know how to do it. Documentation doesn't say much.
Any help will be much appreciated.
disqus:1902807857
Thanks for sharing. I was looking for some info on customizing bootstrap and found this very informative article. Although I consider myself somewhat of a fullstack developer (meaning I have done frontend and backend dev) after reading this post it reminds I how much I love working mostly on the backend these days :)
disqus:2047234271
First of all, thanks for the article. I followed it step by step and didn't encounter a single problem.
To answer Josephine's question: Bootstrap indeed uses css and js (and glyphicons). To build the javascript, you can use Grunt's concat method. It concats javascript files into one file. You can specify the files you want, or simply combine them all (as in my example)
In your Gruntfile.js file add the following lines inside grunt.initConfig({
concat: {
bootstrap: {
src: ['node_modules/bootstrap-sass/assets/javascripts/bootstrap/*.js'],
dest: 'public/assets/js/bootstrap.js'
}
},
As for the glyphicons (and images), you can use grunt-contrib-copy:
copy: {
bootstrap: {
expand: true,
cwd: 'node_modules/bootstrap-sass/assets/fonts/bootstrap/',
src: ['*'],
dest: 'public/assets/fonts/bootstrap/'
}
},
You also need to add this:
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-copy');
And finally:
grunt.registerTask('bootstrap', ['sass:bootstrap', 'copy:bootstrap', 'concat:bootstrap']);
Execute with: grunt bootstrap
=> you can optimize the script some more (like putting the long path in a variable), but this should at least get you going.
disqus:2396008796
Thanks for posting the config for the javascript and fonts!
disqus:2397032014
Thanks for the great article. I'm able to do everything you list, but wanted to know how to then take mystyle.css and minify to mystyle.min.css ?? Any help is appreciated. Thanks!
disqus:2485303138
Great post, finally one that shows how to override boostrap sass variables WITHOUT vendoring bootstrap. I value that a lot, since it will greatly reduce the risk of making custom changes to bootstrap specifics (not in a override file).
disqus:3113995388
Awesome, thanks for the help. This cleared up a lot of confusion I had with Sass file structure + Grunt + Bootstrap all at once.
disqus:3187966744
Greetings, is there a way you could redo an update using Bootstrap 3.3.7 and note if there are any differences after using grunt.
disqus:3478271918
to customize bootstrap themes you can now use my tool https://bootstrap.build , it's 2018
disqus:3681202434