Bootstrap without all the debt
My old coworker Matt Copeland recently wrote an excellent article called Bootstrap Bankruptcy, in which he compares using Bootstrap on a website to taking out a mortgage:
When it comes to custom interfaces, Bootstrap isn't a box of bricks, panels,
walls and doors with which you can build anything you want. Bootstrap is more
like a mortgage. Mortgages can be good things. You didn't have the time to
save up and buy your house in cash. You needed a mortgage to get a roof over
your head. That's similar to using bootstrap to get some UI in place when you
don't have the resources to build UI from scratch.
The way Bootstrap is generally used
Matt here is describing what I would guess the majority of users experience at some point with Bootstrap: what at first seemed like a great set of building blocks eventually starts to morph into a mountain of technical debt. Your HTML is littered with deeply nested structures with Bootstrap-specific attributes like "row"
and "col-lg-10"
. It isn't semantic, and it's difficult to imagine pulling Bootstrap out. In this common case I agree with Matt, and I think an argument can be made that a serious flaw in the framework is how gleefully it seems to facilitate such tight coupling and non-semantic markup.
A big part of the problem, of course, is that Bootstrap uses exactly this kind of markup throughout the examples in its documentation. But I don't fault the Bootstrap developers for that. In my opinion they've optimized for immediate usability—the kind where you can just copy and paste some code and it works right away—and that is a large part of the framework's success. Also, though the framework uses LESS internally for organization and reuse of styling rules, it is distributed mainly as CSS, which requires no additional setup and can simply be dropped into a website for low-friction installation.
These shortcuts are a significant part of why Bootstrap draws so much criticism from some circles (you may not be aware of it, but it's out there if you want to go look for it); paradoxically, they're also a large part of of what has made it so popular. But that's another discussion. On to the promised milk and honey.
A better way to use Bootstrap
Fundamentally, I think it's valuable to conceptualize Bootstrap as two distinct things:
- A collection of carefully-crafted styling rules (think: the CSS properties)
- A vocabulary for referring to those rules (think: the actual class names)
The first really is a set of building blocks. Just look at Bootstrap's website and you can see it all there: typography, spacing, color scheme, basic layout. Forget about class names and special attributes for a moment and just consider what you see. These are all reusable pieces. The trick is how you consume them.
Bootstrap's vocabulary is where we can get into trouble. Using <div class="container">
and so forth directly in your markup is a sure way to end up trapped by some serious Bootstrap lock-in.
To enjoy the benefits of Bootstrap's useful styles, without incurring all the debt of its vocabularity, use semantic markup on your pages and shoehorn Bootstrap's styles in by way of a higher-level stylesheet language such as SASS.
Here's what I mean. Say you have a Bootstrap-y HTML layout like this:
<body>
<div class="container">
<div class="page-header">
<h1>Company Title</h1>
<p class="lead">Slogan</p>
</div>
<div class="row">
<div class="col-lg-3">
<ul class="list-group">
<li class="list-group-item"><a href="/">Home</a></li>
<li class="list-group-item"><a href="/about">About</a></li>
<li class="list-group-item"><a href="/contact">Contact</a></li>
</ul>
</div>
<div class="col-lg-9">
<h1>Heading</h1>
<p>Lorem ipsum dolor sit amet [...]</p>
</div>
</div>
</div>
</body>
Even for something so simple, we've already started down a pretty tightly-coupled path. Let's try starting over, sticking with semantic markup.
<body>
<header>
<h1>Company Title</h1>
<p>Slogan</p>
</header>
<main>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<article>
<h1>Heading</h1>
<p>Lorem ipsum dolor sit amet [...]</p>
</article>
</main>
</body>
There, much better. Now there's no trace of Bootstrap in the markup itself. (Notice I am using some HTML5-specific tags such as <header>
, <main>
and <article>
; if you were _targeting older browsers you could still easily keep your markup semantic by using <div>
elements with meaningful, non-Bootstrap class names.)
Now using SASS we can still style this page using Bootstrap's style definitions by @extend
-ing Bootstrap classes:
// I have no idea why Coderwall is putting a <a href="..."> in here.
@import "bootstrap";
body { @extend .container; }
body > header { @extend .page-header;
p { @extend .lead; }
}
body > main { @extend .row;
nav { @extend .col-lg-3;
ul { @extend .list-group;
li { @extend .list-group-item; }
}
}
article { @extend .col-lg-9; }
}
Here's the result:
Let's try another example: a login form.
<form>
<div class="form-group">
<label for="email">E-mail</label>
<input type="text" name="email" class="form-control" />
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" name="password" class="form-control" />
</div>
<div class="checkbox">
<label for="remember">
<input type="checkbox" name="remember"> Remember me
</label>
</div>
<input type="submit" class="btn btn-primary" value="Log In" />
<a href="../" class="btn btn-warning">Back</a>
</form>
Again, lots of Bootstrap in there: <div class="form-group">
, <input class="btn btn-primary">
, etc. Let's try to be more semantic again:
<form id="login-form">
<div class="email field">
<label for="email">E-mail</label>
<input type="text" name="email" />
</div>
<div class="password field">
<label for="password">Password</label>
<input type="password" name="password" />
</div>
<div class="remember field">
<label for="remember">
<input type="checkbox" name="remember"> Remember me
</label>
</div>
<div class="actions">
<input type="submit" value="Log In" />
<a href="../">Back</a>`
</div>
</form>
And again, we'll borrow from Bootstrap in our SASS:
#login-form {
.field { @extend .form-group;
input[type="text"],
input[type="password"] { @extend .form-control; }
&.remember { @extend .checkbox; }
}
.actions { @extend .form-group;
input[type="submit"] { @extend .btn, .btn-primary; }
a { @extend .btn, .btn-warning; }
}
}
How does it look?
Graduating from Bootstrap
So you can see that you don't necessarily need to clutter your markup with Bootstrap terminology in order to access the framework's handy selection of styles.
That said, of course there is more to the idea of "Bootstrap Bankruptcy" than the tech debt of tightly-coupled markup. Inevitably most sites that develop a significant user- or reader-base will eventually want to graduate from Bootstrap and define their own set of styles. The problem is typically that this can require great effort when Bootstrap is so deeply integrated into every corner of your HTML.
The approach I've suggested, of adhering to semantic markup even while leveraging Bootstrap's style definitions, gives you the best of both worlds. You get to throw together something attractive quickly, building off the work of the Bootstrap team. Then when it's finally time to move on and start work on a custom design, you can throw out the reference to Bootstrap and you'll have a clear, semantic HTML structure to work with.
Related protips:
Written by Dan Tao
Related protips
57 Responses
Food for thought, thanks for the insight.
This is an excellent technique and something I hadn't considered. I was worried about the technical debt I was accumulating with Bootstrap, and was wondering how I could divorce my code from Bootstrap while still using it. Thanks for sharing!
Quality examples of separating the presentation layer. Thanks for the shout out, Dan!
I launched an app pretty quickly this past summer and I used Bootstrap for the layouts and I thought it was frustrating mixing and cluttering all those Bootstrap classes inside my html. I'm using Zurb's Foundation for my next project and it's great because it's built with Sass with the purpose of being customized and extended very easily. With the Sass, you can create your own classes that encapsulate the Foundation styling so you don't have 'framework lingo' scattered everywhere.
This is a great tip, thanks! To anyone thinking about using Bootstrap, take a look at Foundation, and this all comes in the package.
I'm currently using bootstrap on a major project. We're getting a UI redesign, and I am looking at semantic-ui rather than bootstrap, partly because of the way it has decoupled the class names and the element type. Foundation and Semantic-UI are the way I will be heading - regardless of Bootstrap 3.
That's one of the main reasons I prefer Foundation over Bootstrap, the main reason being that it's all written in SASS (personal preference, obviously). All of Foundation's classes are also available as mixins, allowing you to do exactly what you've just described out of the box. Pretty handy, but good job on coming up with a similar approach with Bootstrap.
You can also use LESS, and use Bootstrap's LESS files and mixins.
The problem with using @extend is that your selectors grow to be insanely long, which in turn increases the file size of the compiled CSS file. We recently tried using this extend approach on a previous project and it was a nightmare. CSS selectors within Firebug/Dev tools would sometimes be around 30 long, extremely verbose, and difficult to debug. There's no reason to use @extend in this matter.
You could always try Foundation, or my own Toolkit. http://titon.io/toolkit/
@milesj: I definitely know what you mean. I have also seen myself that @extend
is not a perfect solution because it can sometimes be tricky to figure out what to extend (you have to dig through Bootstrap's source to figure out where certain styles are actually defined).
That said, I would point to my closing remarks about "graduating" from Bootstrap. True to its name, the framework can be useful for standing up a pretty-looking site very quickly, without putting much thought into design. I'm simply suggesting a way to use it for this purpose without incurring all the tech debt associated with having it scattered throughout your markup. That doesn't mean it's a good long-term investment or something you should be spending a lot of time on to get things looking perfect (i.e. inspecting CSS rules in dev tools)--just the opposite, in fact.
To be honest, for a new project where good design is a priority I would likely advise against Bootstrap as well. But more importantly, I would encourage any team on such a project to try not to couple their markup too tightly to any particular framework. And that's really what I hoped to get across in this post.
I've tried this approach with the RailsLayout gem, which generates Rails application layout files for various front-end frameworks, including both Bootstrap 3 and Foundation 4. I use mixins or extend so the markup in the application layout is the same, whether you use Bootstrap 3 and Foundation 4. I'd love suggestions for improving the gem:
https://github.com/RailsApps/rails_layout
Excellent topic and ideal for those we are starting +10!
Great post, thanks. Hadn't thought of using it that way.
Amazing article. This is a simple and genius solution to the problem of using Bootstrap with its over complicated structure.
Thanks for sharing these thoughts. It just blowed my mind! O_O
I think this tip is not just for Bootstrap, but for any other framework, just like UJS for javascript, this looks like a UCSS (Unobtrusive CSS) for me. What means that can be used anywhere. =D
Congrats!
Bootstrap seems to have become less prescriptive over time, but I also prefer Foundation for the reasons you've gone through, here - better integration with Sass and encouragement form the devs that you use @extend to build out your own classes.
Doing a lot of rapid prototyping, I find Foundation to be an incredible tool. Having protoytped up a template layout, it's pretty simple to switch classes to a decent SUIT/BEM naming convention and latch on media-queries too.
Absolutely love the analogy with taking out a mortgage - very true! Great insight.
I started out using Foundation and now have to switch to Bootstrap. Actually I don't use straight Bootstrap but I utilized the Flatstrap version of it. I didn't much of the "debt" in Flatstrap. Foundation has lots of bugs and lack of community support.
I wrote about this very technique nearly two years ago here: http://ruby.bvision.com/blog/please-stop-embedding-bootstrap-classes-in-your-html
I'm currently in the middle of building an app with these techniques. I have had a few occurrences where I still needed to add 'junk' wrapper divs to a few things just to get proper Bootstrap functionality. table-responsive comes to mind, but I think there were one or two other instances of this as well.
"...we can still style this page using Bootstrap's style definitions by @extend-ing Bootstrap classes..."
FYI, LESS has the same exact functionality since v1.4.0. https://github.com/less/less.js/blob/master/CHANGELOG.md
I suppose it's bad to link to other frameworks, but this is essentially what you're talking about:
http://bourbon.io
http://neat.bourbon.io
http://bitters.bourbon.io
what date was this published? it would be helpful to show the date, bcuz web stuff becomes obsolete so quickly.
Nice post. Thanks.
I've read that tag selects are not effective (never tested this point), also extending sass like this would bloat code.
https://developers.google.com/speed/docs/best-practices/rendering
Possibly optimizing some of the css to work with semantics based on your sites mark up might be a good middle of the road solution.
The 'semantic web' was a data-scientist pipe-dream that died with XHTML 2. The only semantics expressed by your markup is in the interface they present to your users. Any effort expended to add 'semantic' value beyond that is wasted effort, that would be better spent improving your product in a way that actually benefits your users.
As for decoupling from Bootstrap, if you ever need to swap out such a foundational part of your application, you have made a serious mistake somewhere. You should choose your core dependencies carefully, then exploit them to the fullest and build on top of them, not waste effort trying to abstract yourself from your choices. Yes, you will accumulate debt, but that is just the price you pay for the advantages that such libraries give you.
I recently used bootstrap in a project and being a bootstrap user since V1 I've faced the un-semantic tag jungle way too often. But nevertheless I keep trying to untangle the tight twitter framework. Sometimes I thought Bootstrap was the ultimate twitter world domination plan, why open-source a framework fully usable only in twitter team's projects? Then I discovered the LESS mixins in the framework and started to use them. At first it went on smoothly and swiftly on wheels, but then I realize the HTML structure and classnames was coupled even in this level. So, now I'm slowly developing a mixin library of my own based in bootstrap. Now I've realized the real value of bootstrap is the concept itself, the mindset they put themselves on creating an easy prototyping framework and it's a project truly committed to one of the open-source foundations: learn to do things.
Foundation has been great for me. I like Bootstrap, but I have had an easier time getting things done with Foundation. Has anyone tried Gumby of Jeet?
I agree with article in general and great info, thanks, but I still think it's a overhead..
I just use default bootstrap compiled css and just load custom css after .. that's it!
I do not like meesing around less .. or sass cose it just ruins my workflow tremendously, even do I like it so much!!!
cheers
Can you explain how you use this technique without losing the JS component integration? At least with Bootstrap 1.x and 2.x, there's also a problem in that many CSS rules are done through wildcard selectors like span-*, and @extend didn't seem to pick them up properly when I tried using it in the style you suggest.
I'm working on a SCSS framework that does essentially this. I hope to have it pull in any number of external frameworks. Nice to see someone else is thinking along the same lines
Some good points. All I do is try to override Bootstrap styling. You can even use :extend() in LESS (that's what I use) like in Sass. Currently I'm looking at Pure (purecss.io), because I like their approach.
Great points on keeping away from the BS terminology and keeping the markup semantic.
Can't say I really agree.
As someone else pointed out, you're not going to get the javascript integration with this. You're also going to blow things like navs which depend upon the relationship between two classes (I originally said grids, but it appears that in BS3, the grid no longer uses class relationships).
Even with a framework like Foundation which seriously drinks the mixin kool-aid, you're going to expend a ton of effort to express what are ultimately Foundation ideas. If you decide to swap out for a different library, then you will have to translate the ideas, I doubt that changing the markup classes is going to be all that hard.
If you start customizing your controls and grids, you can just import your SASS/LESS after the bootstrap. If you get to the point where you are replacing a section of bootstrap more than customizing it, then just don't import that part of Bootstrap.
To append to what biggernoise said, your clean HTML is just an illusion and you are going to missing the Javascript(which is a very important part of the framework). You're still working with a giant framework that is meant to be used in the default manner. Sure the markup doesn't look pretty, but what do you expect from these kinds of frameworks?
In the end, people who like to customize the big frameworks at some point realize that they either need a much more simple framework with very simple and semantic markup or they need to just do it on their own. I used to think I could "fix" Bootstrap, but it's not worth it.
To some of the commenters here, perhaps I am missing something but what is the difference between Bootstrap grids and Foundation grids... Foundation uses "row > small-x large-x columns" while Bootstrap uses "row > col-x col-sm-x col-lg-x". How is one more semantic than the other?
@abitdodgy
Foundation provides a bunch of SASS mixins and the documentation is very clear about how to use them. It's not an afterthought, they appear to have put a lot of effort into this. Essentially, Foundation is designed to do what the author of this article is trying to make bootstrap do.
Nice post! One thing I think why Coderwall try to anchor your @import
is perhaps it thinks you're mentioning to a user import
;)
It seems you're more against the use of classes in general than the specific classes bootstrap adds. All frameworks make use of classes, Foundation does it too. Show me a framework that doesn't use classes and I'll show you one that isn't very flexible.
In your first example, you use type selectors exclusively, which produces selectors that don't perform well, e.g. body > main nav ul li. A class on the nav element would be a good approach here.
This is a fine idea for small sites. For larger sites in which maintainability and reuse are important, the bootstrap method of using UI domain semantic classes makes a lot of sense.
When you think about "semantics" it helps to stop thinking about the semantics of your content (tags do a fine job of describing that) and thinking about the semantics of your UI. How would you describe that UI to someone else? The larger and more complex your site is the more important this is.
Just getting into sass I feel in love with the use of the many smaller semantic grid systems I have seen out there. I would love to see this implemented on bootstrap or foundations!
I am mainly looking for clean and minimalism in my code to add less bulk in creating web apps.
Be careful with using @extend, you create dependencies which in your Sass/SCSS are not visible at what you are extending. This means that when you change properties in the source class you might not be aware that you are changing properties of other classes as well.
@biggernoise I think this article is outdated, or I'm still missing something. I use Bootstrap, and I have no issues with using it semantically. For exmaple:
main {
@include make-row; /* BS mixin */
article.post {
@include make-lg-column(8); /* Also BS mixin */
}
}
I don't see how Foundation is different. Unless we are comparing Bootstrap. Bootstrap since version 2 has offered this functionality and I depend on it now.
The docs are also pretty clear about using the mixins.
@abitdodgy - Bootstrap has a mixin for the fixed grid, but did not (as of V2) for the fluid grid. They have definitely improved the situation for v3, and the documentation is much, much better in this regard. I agree that bootstrap3 is similar to foundation for grids. However, foundation provides this sort of support throughout much more of the library.
Note, that my original point still stands. Any part of the library that depends upon class relations or javascript isn't going to lend itself to semantic cloaking.
IMO, the only thing that all this effort accomplishes is placing a thin veneer over bootstrap ideas. Extracting the classes from the markup isn't what will take a long time should you decide to move on from bootstrap. It's going to be spent replacing the bootstrap ideas.
Great discussion. As long as you've made it this far in the comments, I thought I'd mention another framework comparing itself to Bootstrap's semantic deficiencies -- http://semantic-ui.com/. I haven't used it beyond a brief review, but it looks pretty good on the surface. One really neat feature is the javascript console debugging/tracking which details the performance of animations via console.table
.
I used to freak out about having a clean HTML, but the CSS always ended up being impossible to read and scale. So today I prefer having a few more classes and divs on my html than writing more css. When you break down a HTML into small modules, the cleanness can get in your way of understanding what's going on there. You end up having to refer to CSS that is split between different files.
I'm actually glad I read this. I'm in the process of deciding on a new framework, and it seems that ZURB's Foundation 5 release is going to be better at semantic code. http://foundation.zurb.com
@dtao Great article. Though I think it may be a little narrow in it's focus; which almost gives the impression that Bootstrap is the only framework worth using. (it's not)
@amtiskaw I completely disagree. There has been MUCH interest between web developers on more semantic code. Otherwise this article wouldn't be popular in the first place.
@michaw I am actually working on the official WordPress port for Semantic UI; I have had a much easier time integrating it than when I tried to do something similar with Foundation. Though I haven't used Foundation 5 yet.
Just keep in mind that Semantic UI is designed to be separated out and you should only include the parts you actually used in production. As a base I would get started with grid
, segment
, button
, form
, and menu
from Semantic UI and just add on as needed.
I have to disagree. For example, in the first sample you provide, you show the bootstrap markup, and then the semantic markup. What you're missing is that you're likely going to have to build classes for those elements based on what div you're in. Either way, you're you're styling on an object-by-object basis. As far as stripping out bootstrap down the road - ever hear of Find and Replace?
A framework is almost by definition a dependency that you can't remove without rewriting almost all your app. Trying to abstract over such a fundamental foundation of your site is a highway to hell:
1/ you create your own CSS DSL over Bootstrap so you loose most of the advantages of a framework: productivity and readability due to standardization
2/ you will most likely recreate about the same structure dependencies with your own class names, and the same amount of presentational markup anyway. For the extra effort, you just get the illusion of a slightly more presentation-independant markup. Markup that's presentation-independant enough that it turns out to be worth the effort when you redesign is not a realistic goal anyway in the current state of CSS.
3/ Incidentally you'll fall get some crazy long selectors with the extensive use of @extend.
On the principle it's a bit like trying to abstracting the programmation language away by using a home-made one on top of it, in case you want to change the underlying one some day.
There are some dependencies that should be tied to your app. Choose them carefully.
I think it basically comes down to preference. Classless markup like that is clean and such an eyecandy, I agree. But on medium to large projects, imagine the nest depth on the .scss file.
Again, this is all based on preference, but I prefer to keep my scss nest depth < 4.
Take a look at this: http://thesassway.com/intermediate/avoid-nested-selectors-for-more-modular-css
@abitdodgy you're right in that you can use Bootstrap's classes to extend your own semantic markup. But the problem with that is that you are still going to compile all of bootstrap's bloated, unused styles.
@thomasdobber which is better: having repeated, bloated selectors in your stylesheet or having one place where everything happens? CSS was built for group selectors, and those are faster to render (less to parse). And if you're really that upset about long selectors, check out SCSS sourcemaps.
@zaus I've looked at semantic grid, and while it's better than Bootstrap, it doesn't use mixins, and browser support is spotty. Sometimes they'll support FF2 with -moz-box-shadow</code>, and other times they'll just use box-shadow</code>. I understand that using mixins causes increased coupling, but it saves us the trouble of having to remember which prefixes to write out. It saves us time, and obviously in situations like this one in Semantic UI.
@bingeboy thanks for the link. I should then point out that Semantic UI uses unperformant selectors (namely CSS3). Check out <a href = "https://github.com/Semantic-Org/Semantic-UI/blob/master/src/elements/header.less#L60" title = "last-child selector" _target = "blank">header.less</a>, <a href = "https://github.com/Semantic-Org/Semantic-UI/blob/master/src/collections/grid.less#L346" title = "CSS3 Not Pseudoselector" _target = "blank">grids.less</a>, amongst others. We know, in particular, that the <a href = "http://csswizardry.com/2011/09/writing-efficient-css-selectors/" title = "Not Pseudoselector is slow" _target = "_self">:not</code> pseudoselector is super slow</a>. But that being said, Semantic Grid is still better in terms of its selectors (though they could be grouped for more readable code).
Overall, I think this article explains the resulting technical debt of using Bootstrap. I am <a href = "http://yycjs.com/not-bootstrap/#/unsemantic-bootstrap" title = "Why You Should Stop Using Bootstrap Presentation" _target = "_self">mentioning this in my presentation on why you should stop using bootstrap</a>.
Can you please a tutorial about Startup Framework? http://designmodo.com/startup/
it’s Bootstrap based and have demo version. What do you thinks?
Another issue is that you still need the requisite number of nested elements to hang things off, e.g. for panels - you need a panel heading element with a heading inside, then a panel body div etc., and all of this is likely contained inside layers of row and column divs, regardless of whether you've used less or sass to reassign the styles -- you're still stuck with a hierarchy of elements that's prescriptive.
great article!
What you've done here is trade in tight coupling to Bootstrap's classnames in the markup and CSS selectors, for tight coupling between HTML markup and CSS selectors. I would argue the latter (tight coupling between HTML markup and CSS selectors) is actually more harmful in terms of maintenance.
What if the HTML structure needs to change? In your examples, you've got your CSS selectors deeply nested and tightly coupled to specific HTML elements. This will prove extremely brittle.
Far better to use a CSS naming convention that keeps your selectors short (rarely more than one needed), semantic, and decoupled from your markup.
Rather than rewrite what many others have written about already, I will share a few resources that make the point well:
- https://smacss.com/
- http://nicolasgallagher.com/about-html-semantics-front-end-architecture/
- http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/
@amtiskaw The REAL 'semantic web' was maybe a pipe dream but it has not died, it has simply faded into the background and uses several other names, f.e.: http://linkeddata.org/, http://lod-cloud.net/ etc. etc.
I agree!
The amount of HTML structure Bootstrap comes with is INSANE. It gets super messy. When I started learning HTML, I read a really-really good advice on Smashing Magazine: keep your html minimal. Don't use gazillion containers!
If bootstrap would minimize the amount of html needed, it will be a perfect framework.
Indeed Bootstrap seems a bit messy. If you look through the CSS style applied to a HTML web page you'll see a lot of overwritten rules. So we're also overloading our websites with useless CSS rules.
What I find useful in Bootstrap is the grid system. And that's the reason why I consider this design kit (https://www.froala.com/design-kit) a better way of using Bootstrap (it uses only the grid system).
This is great. I find the challenge though is that the @import causes the boostrap css to be rendered, which I probably won't actually use. If I want my specialized css for different pages in different css files, they will each get the bootstrap css which is even worse.