70

I have been investigating for the whole day as I considered it would be worthwhile spending some time to learn best practice for customizing Bootstrap.

I can see that there is a friendly page available for customizing elements selectively from http://twitter.github.io/bootstrap/customize.html but I want to have more control than this without touching original bootstrap source files.

To start with, I basically wanted to test out changing the grid from 12 to 16 columns and to do this, I created my own variable less file and added @gridColumns:16; only to this file and imported this custom less inside bootstrap.less as follows.

// Core variables and mixins
@import "variables.less"; // Modify this for custom colors, font-sizes, etc
@import "mixins.less";
**@import "../custom-variables.less"; //Override variables**

Then, using WinLess I compiled the bootstrap.less file to get new bootstrap.css with overridden variable import call and linked the css with html file but the grid won't change to 16 columns.

Can anyone please point out what I am doing wrong?

Seong Lee
  • 10,314
  • 25
  • 68
  • 106

4 Answers4

154

Overriding variables after importing the original bootstrap.less works great for me:

@import "less/bootstrap.less";

@body-bg:     red;
@text-color:  green;
@link-color:  blue;

Compiling the above LESS source outputs properly customized Bootstrap CSS code.

Relevant info: http://lesscss.org/features/#variables-feature-lazy-loading

Adam
  • 2,897
  • 2
  • 23
  • 23
  • 22
    This works because LESS variables apply to their current scope on a last-defined-wins basis. Check out the docs for some examples: http://lesscss.org/#-variables – OrganicPanda Dec 02 '13 at 12:51
  • 3
    I never would have thought this would work. The idea of duplicating all the imports from bootstrap.less, with a modified version of variables.less swapped in, was hideous. But as suggested in this answer I can set the variable overrides afterwards (in my case just `@icon-font-path`) and it all works. Thanks! – tremby Mar 10 '14 at 00:17
  • 2
    Doing things this way prevents your changes to variables from applying to bootstrap.css though doesn't it? It will obviously override the variables in any less after your changes, but nothing you change will effect bootstrap itself (post compilation)... – Derek Foulk Jun 19 '15 at 05:48
  • 1
    @derekmx271 No, the changes will affect everything - see the paragraph about [default variables](http://lesscss.org/features/#variables-feature-default-variables) – Adam Jun 19 '15 at 10:06
  • Nice. I didn't realize less vars we're lazy loaded. Good to know! – Derek Foulk Jun 19 '15 at 17:15
  • 1
    +1 I also used to copy/rename variables.less but this is SO much better. This should definitely be the accepted answer. – Daniel Liuzzi Aug 09 '15 at 21:34
  • @derekmx271 I have run into the problem you mention, is there any way around it without modifying the bootstrap variables.less file itself? – Anentropic Dec 20 '15 at 08:49
  • @Anentropic - Checkout this tutorial. This is essentially what I do nowadays... http://www.helloerik.com/bootstrap-3-less-workflow-tutorial. – Derek Foulk Dec 21 '15 at 18:14
  • @Anentropic - In a nutshell, I use Bower to "install" bootstrap (it gets downloaded into a 'bower_components' directory), then I use Gulp or Grunt to copy the b_c/bootstrap/less/* content to my own /src/less/bootstrap/ folder. Then just create /src/less/bootstrap.less file that includes only the Bootstrap .less files you need, create a custom vars.less file (and include that) then use Grunt or Gulp to compile the less files into a custom-bootstrap.css file :) – Derek Foulk Dec 21 '15 at 18:17
  • @SpaceBeers, in Bootstrap-Sass you should define the variables before the @import so the framework checks whether the variable is defined, if so, doesn't change it. e.g.: `$padding-xs-horizontal: 5px !default;` – whoan Feb 26 '16 at 18:24
  • 1
    Great answer! But I'd like to add a little note: People might not want to override the variables in place, but have their own _variables.less_ file, which is included after the _bootstrap.less_ and living in some other directory. You will encounter problems since _variables.less_ (the bootstrap one) will only be included once. So if you use the same file-name in your override-directory, then you will have to put the import like that: `@import (multiple) "variables"`, which tells less to include variables less more than once. – bquarta Mar 12 '16 at 17:19
  • @bquarta Thanks, though I would simply choose a different filename :) – Adam Mar 14 '16 at 10:58
  • @Adam: Jepp, normally this works as well, but there might be cases, where you want to override at many different places in the whole LESS-Structure of Bootstrap, and it might turn out as a good practice to keep the file-structure of Bootstrap "as is", so you quickly can find the corresponding places in your overrides or vice versa ;)... – bquarta Mar 14 '16 at 12:04
  • The "after" is very important. This should be the accepted answer – Cyril Dec 07 '16 at 09:49
43

I work on a similar project where we have bootstrap in a 'third-party' location and then override only mixins.less and variables.less. The pattern we use for this adds three files and doesn't touch bootstrap at all (allowing you to drop in replacements easily):

/style
|- bootstrap-master/
|    |- less/
|    |- js/
|   ...
|- shared/
    |- shared.less
    |- variables.less
    |- mixins.less

the mixins file

/*
 *    /style/shared/mixins.less
 */

@import "../bootstrap-master/less/mixins.less";
// override any mixins (or add any of your third party mixins here)

the variables file, which is where you would override grids

/*
 *    /style/shared/variables.less
 */

@import "../bootstrap-master/less/variables.less";

@gridColumns: 16; // let's pretend this is your site-specific override

The file which is actually imported (or fed through to a less compiler):

/*
 *    /style/shared/shared.less
 */

@import "variables.less";
@import "mixins.less";

@import "../bootstrap-master/less/grid.less";
//and any other bootstrap less files we need here

in my setup, if i do this, i get a css file with some weird .span15 values (since i didn't update @gridColumnWidth or @gridGutterWidth but the .row-fluid values actually work out just the way you'd expect them to since they're calculated by straightforward division).

I like this setup because i can cd into bootstrap-master and git pull and fetch new updates without having to merge any of my specific kludges (it also gives me a good handle on what i've actually overridden)

The other thing is that it's very clear that shared.less is only using grid.less (rather than all of bootstrap). This is intentional since in most instances you don't need all of bootstrap, just a few parts of it to get going. Most bootstrap less files at least are nice in that their only hard dependencies are shared.less and mixins.less

if this still isn't working, then maybe WinLess is getting confused

Marcos
  • 657
  • 6
  • 7
  • Thanks very much for the insights. I've tried your solution and the grid is changed to 16 but the layout is not responsive anymore by screen size. Do you only compile shared.less and link the compiled css below master bootstrap css? Thanks – Seong Lee May 05 '13 at 22:11
  • @SeongLee no problem! i believe that there will be quite a few more less variables that need updating in order to make the new grid work correctly. Only `shared.less` is compiled and pages link directly to that file (or in production, its compiled output). You shouldn't ever have to include bootstrap anywhere else, although you will have to include whatever modules are missing. If you want i can update the answer to make that more clear. – Marcos May 08 '13 at 04:38
  • Thanks @Marcos How do you mean I shouldn't ever have to include bootstrap? If you can, please update the answer for clarification like you said. Thanks a lot! – Seong Lee May 09 '13 at 03:23
1

Another example that may help someone:

@import 'bootstrap/bootstrap/variables';

// Prgress bar
@progress-bar-bg: #f5f5f5;
@progress-bar-default-color: @gray-base;

@import 'bootstrap/bootstrap';
adamj
  • 4,672
  • 5
  • 49
  • 60
-4

An easy way is just to override the styles in your style doc, using the same name, and marking it as !important.

Sterling Diaz
  • 3,789
  • 2
  • 31
  • 35
  • 1
    Overriding styles using `!important` is a terrible idea in general but overriding theme styles using `!important` is even worse. – CervEd Apr 27 '20 at 09:18