Limit the scope of bootstrap styles

How do I limit Bootstrap to just the scope of a div? I need to nest the Bootstrap stylesheet inside an ExtJS app for especific divs and both are clashing since they need their own body, ul, li, a, etc.

I'm trying to avoid editing bootstrap.css manually (or keeping it to a minimum) so that it can be easily updated.


Solution 1:

You can fork the bootstrap repo and change bootstrap.less to wrap the bootstrap styles:

.bootstrap-scope {
    //put bootstrap @includes in here
}

Then, in the root of the bootstrap project, run make to generate the bootstrap.css file.

You'll lose the global styles bootstrap assigns to the body and html tags, but you might not want them anyway.

And then, in your app, give the container you want the .bootstrap-scope class.

Solution 2:

Since the result of modifying less/bootstrap.less was not good enough for me (see why at bottom of post), I ended up filtering bootstrap.css :

var css = require('css'), fs = require('fs');

var prefix = '.bootstrap-scope';
var inFile = 'bootstrap.css';

var cssAst = css.parse(fs.readFileSync(inFile, 'utf8'));
prefixNode(cssAst);
console.log(css.stringify(cssAst));

function prefixSelector(sel){
    if (sel.match(/^@/)) return sel;
    var m = sel.match(/(^| )(body|html)($|\W.*)/i);
    if (m) 
        return m[1] + prefix + m[3];
    else
        return prefix + ' ' + sel;
}

function prefixNode(node) {
    if (node.selectors) {
        node.selectors = node.selectors.map(prefixSelector);
    } else if (node.stylesheet) {
        node.stylesheet.rules.forEach(prefixNode);
    } else if (node.rules) {
        node.rules.forEach(prefixNode);
    }
}

Since bootstrap.css is generated, one can also do it blindly (solution similar to Alexey's, but also handling a few corner cases):

perl -lpe 'BEGIN { $prefix = ".bootstrap-scope" } if (($indent, $s, $sep) = /^(\s*)([^@\s].*?)(\s*[,{])$/) { $s =~ /^(from|to)*$/ or $s =~ s/(^| )(body|html)($|\W.*)/$1$prefix$3/i or $s = "$prefix $s"; $_ = "$indent$s$sep" }' bootstrap.css

As for modifying less/bootstrap.css and calling grunt to generate dist/css/bootstrap.css (Andrew Homeyer's solution), it seems not working nicely (in bootstrap 3 at least) for some cases:

  • various mixins like .make-grid-columns (from less/mixins.xml) end up badly prefixed. Example:

    .bootstrap-scope .col-sm-1,
      .col-sm-2,
      .col-sm-3,
    
  • the usage of "&" in LESS is limited:

    .caret {
      .btn-default & {
    

    becomes

     .btn-default .bootstrap-scope .caret {
    

    instead of what we want:

     .bootstrap-scope .btn-default .caret {
    

Solution 3:

If you have the following file structure:

  • mystyles.less
  • mystyles.css
  • /bootstrap/
    • bootstrap.less
    • bootstrap.css
    • grid.less
    • ...
    • /mixins/

And you want to limit the scope of bootstrap, you have to put in your mystyles.less (right way):

.your-class-to-limit-bootstrap-scope{
    @import (less) "bootstrap/bootstrap.css";
}

We have to import the bootstrap.css file instead of bootstrap.less, but using the (less) @import option in order to treat the file as a Less file, no matter what the file extension. So, you will get the correct css, for example:

.your-class-to-limit-bootstrap-scope .col-xs-1,
.your-class-to-limit-bootstrap-scope  .col-sm-1,
.your-class-to-limit-bootstrap-scope ...
.your-class-to-limit-bootstrap-scope .col-lg-12 {
    position: relative;
    min-height: 1px;
    padding-left: 7px;
    padding-right: 7px;
 }

But if you import bootstrap less files you will get a incorrectly scoped css (wrong way):

.your-class-to-limit-bootstrap-scope{
    @import "bootstrap/bootstrap.less";
}

So, you will get the incorrect scoped css, for example:

.your-class-to-limit-bootstrap-scope .col-xs-1, 
.col-sm-1,
.col-md-1,
...
.col-lg-12 {
    position: relative;
    min-height: 1px;
    padding-left: 15px;
    padding-right: 15px;
}

Solution 4:

There is way much easier way to achieve this legitimate requirement: replace }NEWLINE and ,NEWLINE with previous value and your class scope. It's very easy to to in e.g. Sublime:

  • Select }\r\n

  • Alt + F3 (to select all occurrences)

  • Replace with }\r\n.bootstrap-scope

  • Select ,\r\n

  • Alt + F3 (to select all occurrences)

  • Replace with ,\r\n.bootstrap-scope

That's it! It will be pretty easy to update it going forward since replacement takes about a minute. Hope my answer helped.

Solution 5:

Expanding on @Andrew Homeyer answer:

I got scoped styling of boostrap working in my Reactjs app by doing the following:

  1. Went here and downloaded bootstrap source
  2. Followed the guide here to install grunt. summary:

Bootstrap uses Grunt for its build system, with convenient methods for working with the framework. It's how we compile our code, run tests, and more.

Installing Grunt: To install Grunt, you must first download and install node.js (which includes npm). npm stands for node packaged modules and is a way to manage development dependencies through node.js.

Then, from the command line: Install grunt-cli globally with npm install -g grunt-cli. Navigate to the root /bootstrap/ directory, then run npm install. npm will look at the package.json file and automatically install the necessary local dependencies listed there. When completed, you'll be able to run the various Grunt commands provided from the command line.

  1. Edited the file less/bootstrap.less from the downloaded source to the following:

.bootstrap-scope {...pasted all @imports here...}

enter image description here

  1. Ran grunt dist and copied the new dist folder into my project
    in App.js import './styling/bootstrap/css/bootstrap.min.css';.

enter image description here

Similar discussion here