I’ve been working through this article to organize my front-end code. It references articles on BEM / SMACSS, which in turn reference other articles.
I’m really trying to understand what the best practices are … I have a few days to lay down this “standard”, and then have to burn through a high-priority / high-visibility / limited timeline project. As such, I’d like to ensure I’m starting with a foundation that will scale as my app does.
Given a component named segment
… I’m creating pages that will have ~10 segments
per page. Each segment
will share the same base class. However, certain segments
will have modifiers on them (different background colors). Further, elements within each block (in the BEM approach) will have modifiers as well. To demonstrate, here is a simple implementation (with only a single element arrow
, while my full site will have 4-5 elements in each segment
):
.segment__arrow {
position: absolute;
bottom: -24px;
left: 50%;
margin-left: -11px;
background-position: center no-repeat;
height: 21px;
width: 21px;
z-index: 2;
}
.segment__arrow--orange {
@extend .segment__arrow;
background-image: url('/images/arrow_orange.png');
}
.segment__arrow--white {
@extend .segment__arrow;
background-image: url('/images/arrow_white.png');
}
So this is the single-class approach:
<div class="segment__arrow--white"> ... </div>
Alternatively, I could go with the multi-class approach:
.segment__arrow {
position: absolute;
bottom: -24px;
left: 50%;
margin-left: -11px;
background-position: center no-repeat;
height: 21px;
width: 21px;
z-index: 2;
}
.segment__arrow--orange {
background-image: url('/images/arrow_orange.png');
}
.segment__arrow--white {
background-image: url('/images/arrow_white.png');
}
Where my markup would be:
<div class="segment__arrow segment__arrow--white"> ... </div>
Third, I could do:
.segment__arrow {
position: absolute;
bottom: -24px;
left: 50%;
margin-left: -11px;
background-position: center no-repeat;
height: 21px;
width: 21px;
z-index: 2;
}
.segment__arrow.orange {
background-image: url('/images/arrow_orange.png');
}
.segment__arrow.white {
background-image: url('/images/arrow_white.png');
}
And then my class def would be
<div class="segment__arrow orange"> ... </div>
Perhaps even namespacing orange with something like sa_orange
to avoid loose selectors.
The end result I’m looking for is less code / easier to maintain (which probably rules out the single class approach (option 1), as described in this great article on scalable architecture. The multi-class approach (option 2) results in a lot of verbosity (especially in my HTML), but is extremely explicit. The third uses a multi-class approach, but doesn’t use namespaced modifiers (like .segment__arrow), so is slightly less verbose (but also less explicit & higher potential for collisions).
Does anybody with real world experience with this stuff have any feedback on the best way to approach this?
3
For a long time I have been using and recommending the explicit multi-class approach (the second example) as it is the most universal, maintainable, and coherent. Here I will try to support this claim.
Single-class
This approach has a big problem when there are two or more categories of modifiers. For example a .button with modifiers small, large, huge for size and primary, success, info, and warning for “colour.” On top of the usual 7 (= 3 + 4) classes one has to create all 12 combinations too:
.button--small--primary
.button--small--success
.button--small--info
…
So far a bit inconvenient but not a disaster.
Another annoyance – a bigger one – is that the correct order “size first, colour second” must be used and therefore remembered (and well documented).
The worst is when JavaScript is involved. Want to change the “colour” of this button but keep the current size? Parse the class attribute! Want to just remove the success modifier? Parse the class attribute!
Count that e.g. Bootstrap has 7 “colours”, 4 sizes, and active/disabled states; for which 119 (= 13 + [7*4 + 7*2 + 4*2] + 7*4*2) classes have to be declared in order to maintain single-class approach! That is the big problem.
Explicit multi-class would require just 13 classes (one for each modifier). The order would be arbitrary. Lastly, adding, removing, and changing one while preserving others would in jQuery look like:
$('#login-button').removeClass('button--primary').addClass('button--success');
Shortcut multi-class
Firstly, as you mentioned, there is a potential for collisions – a bad thing by itself.
Secondly, what it also means, is that the .segment__arrow.orange
has a higher specificity and cannot be overwritten with a single class selector. This is often in issue when an element is e.g. not only a large button but also e.g. a login button. Its code would look like:
<a href="#" class="button large primary login__button">Log in</a>
One might want to have a bigger left and right padding on the login button but preserve the height of large. This would result in more and more specific selectors which would bring us to the specificity hell – a place OOCSS should save us from.
It is evident this would not happen in the explicit multi-class approach.
Explicit multi-class
The only problem (as far as I am aware of) of this is that there are a few sometimes quite long classes in the markup. I do admit this.
Let me note that this is only a matter of taste of the developer as it has a negligible (to no at all) effect to the performance. The standard compression will take care of this.
That being said, using a good IDE will help to write these (yes, I know, it still will look a bit ridiculous).
On one hand, I would say, seeing such long classes forces one to think more about the structure; e.g. whether it would not be better to introduce a new (reusable) component instead of nesting it into something else.
I am debating with my teammates about this Single/ Multi Class issues right now
here are some of my personally views based on best practise
Best Practise
- html declares elements
- CSS controls render
Single Class is always following the Best Practise
with extra maintaining benefits, with good names it can achieve
-
style change requires no html update*(see demo)
-
locking style in html(you will have the right style or nothing)
Demo
@mixin segment__arrow {
position: absolute;
bottom: -24px;
left: 50%;
margin-left: -11px;
background-position: center no-repeat;
height: 21px;
width: 21px;
z-index: 2;
}
.segment__arrow--type1 {
@include segment__arrow;
background-image: url('/images/arrow_orange.png');
}
.segment__arrow--type2 {
@include segment__arrow;
background-image: url('/images/arrow_white.png');
}
@mixin include is better than @extend
- have control of code order in final css
- smaller size in gzip version
and same as @extend, it is can be reused and can replace multi class in HTML
with @mixin, you will gain extra flexibility
@mixin segment__arrow--type1 {
@include segment__arrow;
background-image: url('/images/arrow_orange.png');
}
@mixin segment__arrow--type2 {
@include segment__arrow;
background-image: url('/images/arrow_white.png');
}
.segment__margic-arrow {
@include screen(mobile) {
@include segment__arrow--type1
}
@include screen(desktop) {
@include segment__arrow--type2
}
}
For javascript use
state rules of smacss
Drawback of Single Class
one and only:
bigger CSS files size, BUT you can always easily optimise CSS based on website sections or components in the page