286

I'm working with Bootstrap 2.0.3 using LESS. I want to customize it extensively, but I want to avoid making changes to the source whenever possible as changes to the libraries are frequent. I am new to LESS so I don't know how its compilation entirely works. What are some best practices for working with LESS or LESS based frameworks?

home
  • 12,468
  • 5
  • 46
  • 54
ATL_DEV
  • 9,256
  • 11
  • 60
  • 102
  • Greetings from the future! Bootstrap customization "best practices" have changed in SASS based 3.x and 4.x: https://stackoverflow.com/a/50410667/171456 – Carol Skelly Jul 13 '18 at 13:08

7 Answers7

181

My solution is similar jstam's, but I avoid making changes to the source files when possible. Given that the changes to bootstrap will be frequent, I want to be able to pull down the latest source and make minimal changes by keeping my modifications in separate files. Of course, it's not completely bullet proof.

  1. Copy the bootstrap.less and variables.less to the parent directory. Rename bootstrap.less to theme.less or whatever you want. Your directory directory structure should look like this:

    /Website            
         theme.less
         variables.less
         /Bootstrap
         ...
    
  2. Update all the references in theme.less to point to bootstrap sub-directory. Ensure that your variables.less is referenced from the parent and not the bootstrap directory like so:

    ...
    // CSS Reset
    @import "bootstrap/reset.less";
    
    // Core variables and mixins
    @import "variables.less"; // Modify this for custom colors, font-sizes, etc
    @import "bootstrap/mixins.less";
    
    // Grid system and page structure
    @import "bootstrap/scaffolding.less";
    @import "bootstrap/grid.less";
    @import "bootstrap/layouts.less";
    

    ...

  3. Add your CSS overrides in the theme.less file immediately after where they are included.

    ...
    // Components: Nav
    @import "bootstrap/navs.less";
    @import "bootstrap/navbar.less";
    
    // overrides
    .navbar-fixed-top .navbar-inner, .navbar-fixed-bottom .navbar-inner {
        border-radius: 0 0 0 0;
        padding: 10px;
    }
    
    .nav-tabs, .nav-pills {
        text-transform: uppercase;
    }
    
    .navbar .nav > li > a {
        text-shadow: none;
    }
    
    ...
    
  4. Link to theme.less instead of bootstrap.less in your HTML pages.

Whenever a new version comes out, your changes should be safe. You should also do a diff between your custom bootstrap files whenever a new version comes out. Variables and imports may change.

Derek Shockey
  • 1,837
  • 17
  • 15
ATL_DEV
  • 9,256
  • 11
  • 60
  • 102
  • Is there a specific reason for #3? What happens if all your custom css appears at the bottom after all the imports, instead of being intermingled after each import? – AaronLS Oct 16 '12 at 21:13
  • 2
    @AaronLS: That should work too. I think number 3 is for keeping it organized. – Jonatan Littke Oct 31 '12 at 08:44
  • @joelrodgers Why should mixins.less not be directly edited? – Joe Isaacson Jun 22 '13 at 19:35
  • What do you think about include an empty variables-custom.less file (via @import) inside bootstrap.less ? Then everyone will be able to customize the default Bootstrap variables and update it safely. Anyway I think this feature must absolutely be include in Bootstrap. – adriendenat Jul 31 '13 at 13:40
36

This is something I've struggled with as well. On the one hand I want to highly customize the variables.less file with my own colors and settings. On the other hand, I want to change the Bootstrap files a little as possible to ease the upgrade process.

My solution (for now) is to create an addon LESS file and insert it into the bootstrap.less file after the variables and mixins have been imported. So something like this:

...

// CSS Reset
@import "reset.less";

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

// Custom Addons
@import "addon-file.less"; // <--- My custom LESS addon

// Grid system and page structure
@import "scaffolding.less";

...

This way if I want to reset Bootstrap colors, fonts or add additional mixins I can. My code is separate yet will be compiled within the rest of the Bootstrap imports. It's not perfect, but it's a stopgap that's worked well for me.

jstam
  • 561
  • 3
  • 3
  • 1
    Good solution. This is exactly what I did with some changes. Look at my answer. It was too long to put in a comment. – ATL_DEV May 08 '12 at 19:38
  • I like your solution as well, Joel. Nice separation of your code versus the code of the framework. – jstam May 10 '12 at 13:59
  • Since mixins references variables, would I need an additional custom-variables.less between variables.less and mixins.less import? So that I can modify variables like @baseFontSize. I don't even know enough to know if it will choke on me declaring a variable of the same name again. – AaronLS Oct 16 '12 at 22:14
  • I found this to be the most helpful solution because per a new copy of bootstrap, we simply have to add one line again to `bootstrap.less`, grabbing our customized file VS potentially changing many lines if the core less file names change, etc...I used this solution, recompiled my minified JS using grunt and all is good in the hood! Customizations working without any not-friendly `!important` statements! – twknab Mar 24 '17 at 05:02
25

From my side, I just have a file named theme.less with an import of boostrap.less in it, and just below I override (even if it seems to be bad using LESS, but well, it's easier to maintain) the variable value I wan't to update.

This works well for having custom values for variables in variables.less

After that I compile my theme.less file instead off bootstrap.less

Example theme.less:

@import "path/to/my/bootstrap.less";  
@linkColor: #MyAwesomeColor;  
Jeromy French
  • 11,812
  • 19
  • 76
  • 129
sam
  • 3,498
  • 3
  • 22
  • 19
  • 1
    This is the way to 1) have a copy of bootstrap code that can be updated at will while still 2) being able to impose your own custom settings. See http://stackoverflow.com/questions/13809895/how-can-i-customize-twitter-bootstraps-css-using-lesscss-variables for details on folder structure. – Jeromy French Dec 12 '12 at 22:39
  • I made sure to put this *before* my own less code to ensure bootstrap wasn't overriding it. – Aram Kocharyan Jul 18 '13 at 10:23
  • This worked great for me. I just pointed Koala at theme.less and it compiles every time I save. – ow3n Jan 07 '14 at 19:17
  • In case someone is using the SASS version, watch out for **!default** – prasanthv Mar 04 '16 at 02:37
5

A far better (IMHO) approach is to take cue from the Bootswatch github project called swatchmaker. This project is specifically tailored for building and managing the dozens of Bootstrap themes on the website.

The Makefile in the project builds swatchmaker.less (you can rename it to something like customizations.less). This file contains a bunch of imports:

@import "bootstrap/less/bootstrap.less";
@import "swatch/variables.less";
@import "swatch/bootswatch.less";
@import "bootstrap/less/utilities.less";

You can rename the swatch folder and bootswatch.less files to whatever you find appropriate.

This makes sense since you can upgrade Bootstrap without affecting your own files. In fact, the Makefile also contains commands to fetch the latest version of Bootstrap. See the README on the project page for more.

As a bonus, the README also suggests that you install the watchr gem which will automatically build the project when a .less file changes.

aleemb
  • 31,265
  • 19
  • 98
  • 114
4

If (AND ONLY IF) you have the time you can do it as I do. I keep my own modified version of the framework(s) and with every update of the framework I read the docs and check the source for modifications.

This solution might sound less ideal on the first look but I have my reasons to do so. I don't work with one but an amalgam of many frameworks, best practices, resets/normalization style sheets etc. and I am always sure that no update will ever change existing projects in any way I didn't see coming.

I'm working on and with my own custom framework for the following reasons.

  1. I strip out every little bit I don't need to keep stuff modular and small
  2. I use my framework for client jobs and want to a) know what exactly I'm working with while b) owning everything I sell to the client. I don't simply copy and use frameworks but try to understand and recreate them
  3. I use my framework in combination with a CMS and can't simply drop and forget a framework into a project / start from scratch
All Bits Equal
  • 731
  • 2
  • 10
  • 26
  • Yeah, I understand, but for me things are changing so fast that all this web technology is becoming a bit overwhelming to keep track of. – ATL_DEV May 10 '12 at 04:54
  • 1
    As mentioned: my approach is only for those who keep tabs on current development of multiple frameworks. I do that because I have to stay on top of development and different approaches to technical challenges. I think this is better suited for framework developers then freelancers that just "want to get the job done". – All Bits Equal May 15 '12 at 09:43
4

I came to the same solution as Joel:

Custom Less Files

Just like described above: I create local copies for all Less files i am customizing: Such as: "variables-custom.less", "alerts-custom.less", "buttons-custom.less". So i can use some standards and have my own additions. The downside is: When Bootstrap will be update it's really hard to migrate.

But there is something else:

Override Styles

When looking around for work-flows i often see people suggesting to simply override styles. So you import the standard Less files first and then add your custom declarations at the bottom. The upside here is: It's easier to update to a newer version. The downside is: The compiled CSS file includes all the overrides. Some CSS selectors are defined twice. So the browser needs to do some lifting to find out what to apply actually. That's not really clean.

I am wondering why preprocessors are not clever enough to solve such double declarations? Is there any better work-flow i am missing here?

Frank Lämmer
  • 2,165
  • 19
  • 26
  • 1
    I see you're point, but you can always run a CSS cleaning utility online or locally. Here's a list of them: http://stackoverflow.com/questions/135657/tool-to-identify-unused-css-definitions You probably don't want to a less compiler running in product anyway. – ATL_DEV Jul 16 '12 at 19:54
  • thx for the reply, wasn't aware that there are dust-me tools. cool, i'll dig into it. Actually i use a less compiler locally anyways (CodeKit). Don't want to compile the css twice. – Frank Lämmer Jul 23 '12 at 15:35
2

Just add @import "../../styles.less"; (or wherever your stylesheet is) to bootstrap.less at the bottom. This allows you to use Bootstrap mixins like .gradient or .border-radius inside your own styles.less.

dallen
  • 2,621
  • 7
  • 37
  • 47