The increasing need for speed in developing responsive, mobile-friendly websites recently shifted more and more web developers towards the use of some advanced CSS-based framework and/or boilerplate like Bootstrap, Foundation, Gumby, YAML, Skeleton and many others. Each one of them offers a wide amount of full-baked classes and selectors to fullfill almost any UI-related task and eventually reach the ultimate goal: make your website look great on every major platform and device without losing anything to any major desktop browser without losing years working to the front-end - and countless nights running client-based tests.
This is why all the aforementioned framework are born, and chances are they will greatly help you achieving such a great result... unless their class and selector names conflicts with yours (and/or other's) already existing css files.
The issue.
Let's take the Bootstrap framework, likely the most-used one up to this day. Here are some of it's interface-related CSS classes:
1 2 3 4 5 6 7 8 9 10 |
.alert .btn .open .close .label .modal .progress .progress-bar .pager .hidden |
... and more.
Needless to say, any of these is full of parameters who will most likely break some egg in other classes sharing that same name... Being them in one of your css file, shipped with some fancy JQuery plugin or included in any other client-side library or module.
The fix.
The first thing that comes to (almost) everyone's mind is the dreadful "find & replace" workaround. We start with renaming "our" offending classes, then we switch to those inside the plugins / modules / libraries trying to make everything work togheter without hassles. Is that a good approach? For a very small website, maybe. But if we're talking about a decently-sized project we can say it's definitely a no-go.
Despite what it could seem, we're talking about a long, delicate and often risky business. You won't often be able to perform such a task automatically, especially if your site contains Javascript scripts who use class selectors to fullfill their job and you could easily miss like the one in the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$(function() { $(".parent").on({ "click": function(e) { var sp = $(this).parent().find(".sibling-panel"); if ($(this).hasClass("close")) { sp.show(); } else { sp.hide(); } } }, "a[class^='btn']"); }); |
Unless you're willing to take these risky roads we suggest to adopt a much more robust, secure approach. The next part of this article will show you how you can encapsulate any existing CSS file - yours or shipped, as long as it can be locally hosted - in its own dedicated Namespace. In order to do this we're going to use a CSS pre-processor among those currently available: the most used up to these days are undoubtely SASS, well-known between Linux environments, and LESS, which is probably the best choice for those working on Windows since its flawless integrated with Visual Studio 2012 (and above) thanks to the wonderful Web Essentials extension add-on.
What's a CSS pre-processor? To keep it simple, we're talking about a code compiler who can build a valid .css stylesheet file starting from a .scss or .less source: the latter is basically a stylesheet file itself with many additional features obtained thanks to a script-alike proprietary syntax. The pre-processor will read these instructions and use them to build a fully-compatible CSS file.
Here's an example of a .less file:
1 2 3 4 5 6 7 |
$font-stack: Helvetica, sans-serif; $primary-color: #333; body { font: 100% $font-stack; color: $primary-color; } |
And here's the .css file built upon it:
1 2 3 4 |
body { font: 100% Helvetica, sans-serif; color: #333; } |
A full reference guide with a lot of working examples is available on either pre-processor's web site:
We'll just stick to what we need to do in order to define our namespace. The syntax, let alone the file extensions, is identical. In the following example we used .less:
1 2 3 4 |
.namespace-name { @import 'css-file-1.less'; @import 'css-file-2.less'; } |
Once built, the resulting CSS file will contain all the selectors defined in the two included files: the .namespace-name class will also be prepended to any of them, meaning that it will be taken into account only inside a container element (DIV, BODY or any other) with the .namespace-name class.
Let's go further: considering the above example, here's how we can create a namespace for the Bootstrap framework's CSS files:
1 2 3 4 5 6 7 8 9 10 |
.bootstrap { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; line-height: 1.428571429; color: #333333; background-color: white; @import 'bootstrap.less'; @import 'bootstrap-theme.less'; } |
The first rules (before the two @import) are those applied to the BODY element by the bootstrap.css file and therefore inherited by any other in-page elements. The only way we have to reproduce that same behaviour is to add them directly to our namespace class. Once we did that, we are free to add the .bootstrap class to the BODY or anywhere we want to be able to use the Bootstrap styles.
Here's an actual implementation example using the sample conventions defined above:
1 2 3 4 5 6 7 |
<div class="bootstrap"> <!-- inside namespace - styles will work --> <button class="btn btn-success">That's it!</button> </div> <!-- outside the namespace - styles will *not* work --> <button class="btn btn-danger">Not going to work</button> |
As explained by the comments, only the bootstrap styles within the .bootstrap div element will be applied.
IMPORTANT: Notice how, just like the "main" namespace file, all the included files also need to have the extension supported by the choosen pre-processor in order to work. If you want to import a standard .css file you can always rename it accordingly: the pre-processor will seamlessly compile them - after all they're just augmented stylesheet files themselves. If you chose .less you can also avoid the rename: just use @import (less) instead of @import as explained here.
Happy coding!