class=“col-md-6” considered harmful

Mykola Oleksiienko
codeburst
Published in
3 min readJan 23, 2018

--

Assigning multiple classes for HTML node is a common technique. It was Bootstrap that made this normal and popular:

Then CSS preprocessors came with lots of handy features. Now CSS-in-JS is getting more and more popular, however, the multiple-class-approach is still in use, not only in Bootstrap itself, but also in layout templates(built on Bootstrap), other CSS libraries etc.

There are two main reasons why I consider this approach harmful. The first, minor, reason is my HTML code(JSX, Handlebars template etc.) gets overblown with unrelated styling info. The other bigger issue is that such styles are difficult to extend and inherit.

Consider this typical Bootstrap example:

Say, we need to customize our first button slightly, e.g. change the padding and margin. We add custom class for first button and some styles for it.

This will not work as expected. The margin will be set, but the padding will be overridden by Bootstrap style, as it has more specific selector. This is what you’ll see when inspecting button’s style in DevTools:

There are two ways to deal with this: use inline styles(which will make your HTML even more bloated with styling), or try some tricks like increasing the complexity of your CSS selectors, which definitely doesn’t smell good(or sell your soul to the devil and use !important).

Maybe, preprocessors can help us?

In SASS I might use @extend to apply Bootstrap styles for my custom class:

This allows to assign only one class for each HTML node, but the issue with style overriding remains. The only CSS preproccesor that can save us is… LESS! And its awesome feature of using any classes as mixins.

Clear. Concise. Works as designed.

Unlike @extend in SASS, which creates enormously large selectors, LESS compiles styles for each selector keeping right priority: your styles will always override the style from included classes.

This LESS feature is underestimated and seldom used nowadays. However, it can solve a lot of issues, which people try to manage with special tools and techniques like CSS Modules, BEM etc.

I introduce an approach called “Semantic modular CSS”. Its simple rules are:

  • give only one class to your HTML nodes
  • the name of a class should reflect not “how it looks”(“.right-column”, “.btn-red”) but “what it is”(“.popup”, “.cancel-button”, etc.) — a role element plays in interaction with user(that’s why I call it “Semantic CSS”)
  • customize your classes by mixing other classes(Bootstrap or any other library of your own stylebook) and adding styles in CSS. Now the best(the only?)way to do it is to use LESS class-as-mixin feature.
  • give the root node of each component a class with unique name according to a convention(%someCamelCaseName%Component, e.g. “.loginFormComponent”. I use camel case intentionally to distinguish root classes from all the other)
  • put all your class definitions inside one of the modules’ classes.

These ideas are not new, you probably used most of them in your styles. I just want to emphasize on the effect you’ll get when combining all of them together.

As you see, in many cases you don’t even need to assign classes to nodes, you can just set styles relying on root class and tag name.

If you use inheritance and you want to create child component, you can easily inherit the styles:

The advantages of this approach are:

  • robust HTML code, reflecting structure, not appearance
  • modular flexible well-structured CSS with inheritance
  • no classnames collision(because all classes are contained inside root component class with unique name), it means that
  • there’s no need for classnames “obfuscation”, your classes remain readable

HTML and CSS become really separated. E.g., after JS developer creates the structure of a component, an HTML coder can start working on implementing design — and it won’t cause any changes in HTML, only in CSS. Or, vice versa, if the JS developer starts working after the HTML was created, he sees clear structure without unnecessary details.

This approaches also makes long BEM-style classnames useless. Instead of using names like .stick-man__head or .stick-man__arms, you set .stick-man as a root class of your component/block, and .head and .arms as nested classes.

Semantic modular CSS approach is suitable for most of modern libraries and frameworks, like React or Vue. And you can get all this goodness out-of-the-box, without any plugins, you only need LESS and a couple of conventions.

Enjoy!

--

--