This post has its origin in a Twitter argument over Bootstrap.
My opponent’s four key points were that:
- Web interfaces are created by combining a finite number of components.
- Bootstrap is a component library that is large enough to meet the needs of almost any website.
- It means you can take Bootstrap, adjust the theme to suit your needs and use it as a base for any website you can think of—just add a couple of custom elements and it will work perfectly.
- Therefore, as long as Bootstrap is used, there is absolutely no point in using CSS methodologies like BEM, OOCSS, SMACSS and others—Bootstrap alone will solve any possible frontend problems.
I completely agree with the first point: interfaces do consist of components, and it is a good idea to think about them this way. However, I can’t completely agree with the other three.
Of course, using nothing but Bootstrap can be a good idea for some projects, but certainly not for most of them.
It was not the first time that I encountered this idea. So, I thought it would be better to write one big blog post, that could later be used as reference material, rather than dozens of tweets. I hope upon reading this text at least some of the readers will start to ask—will my project really benefit from Bootstrap or not, instead of including it into their each and every project.
Problems with CSS
In an ideal world, it would make no difference what you use to and how you write your component library. Once you dealt with styling form elements, buttons and other components, you would only need to reuse them in as many places as possible. Unfortunately, in the real world, it does make a difference since CSS has a number of problems that, unless addressed properly, make such reuse impossible. Those problems are:
Global namespace
Backend developers are used to the fact that everything introduced into a file remains there for good. However, everything written in CSS and JS files goes straight to global namespace and will eventually cause trouble, if not addressed properly. Recently, JS has started to use modular systems to solve this problem.
With CSS, it is far more complicated, though. In an ideal world, we would be using Shadow DOM and Web Components all the time to take care of it. But as long as they are not fully implemented everywhere, the only way to deal with it is by applying a system approach when naming selectors so that possible conflicts occur as seldom as possible.
Cascade
If several rules can be applied to an element, they all will be applied to it one after another. For instance, an h1.title
element will be subject to all the h1
tag and .title
class rules. Since HTML is nothing but tags, a rule applied to tags without class attributes is a rule applied to every single element with such tag.
Hence, applying CSS rules to a tag is not unlike changing object prototypes in JS—and this is exactly what Prototype.js was so much blamed for. The rules will be applied to every single object. Should you change them, it will be as if you have changed the method used by all of its child objects. Trouble is inevitable.
Nested selectors
You can have the following selectors in your CSS: .nav .item {...}
and .menu .item {...}
. The way .item
will be rendered depends on its parents in the HTML page. Everything will go smoothly until you insert your menu
along with its items into the tag with the nav
class. This is where side effects go wild.
Using nested selectors can be compared to using a weird programming language function that returns different results based on where the caller is located in the code: in one place sum(2, 2)
will return 3
; in another place it will return 5
!
How these problems are usually solved
To deal with such side effects you do need a CSS methodology. Good methodology guarantees no such problem is to occur.
Below I will describe how BEM naming conventions can help in solving these problems; keep in mind that this is not the only solution: CSS Modules, Polymer and React solutions based on inline styles can be also used, provided you know how to.
- According to the BEM conventions, you can’t use tags as selectors. Nor use ids, since such elements cannot be used more than once per page. And you never know how many you will need until you try. Thus, CSS rules can only be applied to classes.
- In BEM, you create your own virtual namespace for all of the component elements by prefixing all its class names with the component name:
.nav__item
,.menu__item
. Such prefixing prevents most naming conflicts. - A separate folder is created for each component. It prevents name conflicts and, if used properly, guarantees that there won’t be more than one component of such prefix in the global namespace.
- BEM has only got a single type of nested selectors—element in a modifier-containing block. They look like that:
.component_modifier .component__element {}
. However, even in this case, both classes have to begin with the same prefix, both are kept in the same file, and both have no influence on other components.
These rules allow you to work with independent components that won’t break if being used in different parts of the website together with other components.
Bootstrap, what it is and how it works
Bootstrap is a collection of ready-to-use components (buttons, elements, forms). Being one of the biggest libraries of the kind, it is widely used in many areas.
If you don’t intend to use anything but standard Bootstrap elements, Bootstrap is of choice. Its range of application covers CMS, CRM, simple websites of open source projects, fast prototypes and the likes.
However, it is not the best idea to use Bootstrap if the website has a complex design, non-standard components or complex combinations of such components (for instance, if there are A/B tests using a number of alternative component designs and page layouts). This is because Bootstrap was not made to extend.
Its rules are meant to be short and simple, not independent and extensible:
- Bootstrap redefines the visual styles of essential tags such as headers and form elements.
- Bootstrap often changes the way an element is rendered based on what its parents are. At least, it has recently started to use the
>
rule in selectors. However, things like that make the work with it unpredictable and obstruct redesign. - Bootstrap floods global namespace with hundreds of generically named classes, such as:
.table
,.dropdown
,.row
,.left
, etc. You have to keep these class names in mind and avoid using them while extending your CSS or you will have some unexpected surprises down the road.
When Bootstrap can cause problems
Let’s walk through some examples when Bootstrap is harmful rather than useful. The list does not include all possible scenarios but I think you get the idea.
1. Large scale e-commerce and news websites
The key performance indicator of an e-commerce site is its conversion rate. The conversion rate is significantly affected by the design of a product page and purchase process implementation. Increasing the conversion is of extreme importance since a half percent growth can be enough for a business to employ twice as many front end developers as it has have.
Such things are never achieved by restricting design opportunities. On the contrary, the more room for experiment, the better. Allow your designer to experiment with different variants, let them run 50 split tests at a time. Encourage trying different indents, font sizes, custom elements, etc.
If there is no methodology to supplement Bootstrap, any attempt at doing something like this is likely to break things in the currently invisible parts of the website or in rare page states. Most of the time will be spent in trying to get the better of Bootstrap and its local reassignments.
Examples:
- amazon.com: thousands of pages, hundreds of split tests, continual redesign.
- gog.com: few standard elements and quite a number of custom ones.
- nytimes.com: tons of complex components and exceptions. Several key screens whose design affects the KPI. As well as most large mass media websites.
2. Websites with complex components reused in different places
Quite often components to be reused are not buttons or forms but something complex. Significantly more complex. For instance, posts or comments on Facebook. Bootstrap won’t help you protect them from side effects. You will still need to use a methodology.
On the other hand, putting this component into a new place can cause much trouble. For example, take a complex component that uses .form-control
or label
and put it into a modifier-containing form. A bunch of side effects won’t be long in coming.
It is amazing how much trouble one can get when trying to make a drop-down component (like the unread messages list in Facebook) and put it in a “hidden” state into a header next to the button that activates it.
Examples:
- Gmail: few standard controls, a lot of custom controls, many exceptions, legacy support.
- trello.com: many complex components, a few standard Bootstrap ones.
- In the case of discourse.org its use is also questionable.
3. Websites that have a lot of page types and may need redesign
Once again—e-commerce sites, large online magazines or newspapers, city web portals.
Suppose you are working on the Steam Store website and have decided to change the visual style of headings. You have changed the font size of h1
and h2
(this is how you do headers in Bootstrap). And now you need to check more than a hundred of pages to ensure nothing has gone wrong, and everything is in its place!
Apart from that, you mustn’t forget that some Bootstrap components can reassign the css rules applied to the nested headers, and it needs to be tested for as well.
You wouldn’t be able to gradually (page by page or page part by page part) shift to a new design with standard Bootstrap elements, like headers, kept in use.
An example:
- kickstarter.com: in the last few years, the website has undergone two total redesigns, not to mention small local experiments.
4. Promo sites and landing pages
The only Bootstrap features we might need here are headings, a couple of buttons and a couple of form fields. The rest is parallax, video, large icons and things like that.
Therefore, instead of speeding up your work, you will be losing time in a fight with different Bootstrap side effects.
An example: Official Moscow website
Bootstrap does have its area of application. However, this area is not as wide as some people believe it to be. Indeed, It can be used for about 20% of websites, and it is possible to apply it for another 20%—not without trouble, of course. But for the rest of cases Bootstrap can be a really bad choice.
One should always bear in mind that projects start as something simple and predictable—and later, as time goes by, they change beyond recognition. In the case of Bootstrap, it will be a huge problem while in the case of BEM or CSS Modules it will simply keep working.