The best introduction to BEM is from Harry Roberts:
BEM – meaning block, element, modifier – is a front-end naming methodology thought up by the guys at Yandex. It is a smart way of naming your CSS classes to give them more transparency and meaning to other developers. They are far more strict and informative, which makes the BEM naming convention ideal for teams of developers on larger projects that might last a while.
Since Sass 3.3, we can write things like this:
.block {
/* CSS declarations for `.block` */
&__element {
/* CSS declarations for `.block__element` */
}
&--modifier {
/* CSS declarations for `.block--modifier` */
&__element {
/* CSS declarations for `.block--modifier__element` */
}
}
}
As long as CSS rules are short and base selector is simple, readability remains okay. But when things get more complex, this syntax makes it hard to figure out what’s going on. Because of this, we might be tempted to build two wrapper mixins for our BEM syntax:
/// Block Element
/// @access public
/// @param {String} $element - Element's name
@mixin element($element) {
&__#{$element} {
@content;
}
}
/// Block Modifier
/// @access public
/// @param {String} $modifier - Modifier's name
@mixin modifier($modifier) {
&--#{$modifier} {
@content;
}
}
Rewriting our previous example with our brand new mixins:
.block {
/* CSS declarations for `.block` */
@include element('element') {
/* CSS declarations for `.block__element` */
}
@include modifier('modifier') {
/* CSS declarations for `.block--modifier` */
@include element('element') {
/* CSS declarations for `.block--modifier__element` */
}
}
}
Note that quotes around strings are optional, we only add them for extra readability.
Now, if you feel like element
and modifier
are too long to type, you can create two shorter aliases like so:
/// @alias element
@mixin e($element) {
@include element($element) {
@content;
}
}
/// @alias modifier
@mixin m($modifier) {
@include modifier($modifier) {
@content;
}
}
Using aliases:
.block {
/* CSS declarations for `.block` */
@include e('element') {
/* CSS declarations for `.block__element` */
}
@include m('modifier') {
/* CSS declarations for `.block--modifier` */
@include e('element') {
/* CSS declarations for `.block--modifier__element` */
}
}
}
Wouldn’t the second &__element produce .block–modifier__element?
Fixed, thank you very much!
Wrong. Tuto. 1st reply is right. modifier is always in last position.
And usage of mixins gives unnecessary complexity.
I don’t understand why we have to over complicate Sass code. This makes newbies want to run. The default way is shorter and very simple to understand…
.block {
color: black;
&__element { border: 1px solid; }
}
&__element
might be simpler to understand for you, but for newbies like you said, such syntax might be unfriendly. Let people choose their own tools.totally agree with you, introducing mixins makes it less readable
100% agree with luis. This is not solving a problem, in-fact it’s complicating things. The time it would take a ‘newbie’ to learn what this mixin does they could have figured out what
&__element
does. I mean they still have to add the class to the HTML right?!?I disagree with luis. I do believe that newbies should learn how to use &__ before those mixins, just like they should learn CSS before learning SASS/LESS.
I think that those mixins come in handy when you’re not new anymore, and you want to make your code more semantic and to make more sense – and enable your brain to understand quicker what each line means with simple English.
Plus, when using SASS syntax, those mixins are very short and quick to use:
This to me would seem overly more complex as opposed to declaring an ampersand for a “newbie”. How is a “newbie” expected to know how to write mixins and includes as opposed to simply figuring out that they can pass an ampersand for nesting selectors?
@include m('modifier') { ... }
is still more costly (and unnecessary) fluff as opposed to simply writing out a simple declaration. This, if anything, encourages people, or “newbies” to use costly manoeuvres to start nesting everything. Pretty much contrary to the article seen here.Could be overseeing this as actually “useful”, but I’m open to opinions! :-)
Cheers.
… and, a now even more unsearchable code base, which brings me back to how useful comments are when nesting selectors — again, contrary to the above article reference. Hmm. I need convincing! Haha.
Hey guys, did you notice that they’re now using a single underscore “_” instead of double dashes “–” for modifiers?
http://en.bem.info/method/definitions/
Actually, I’m not against this even if I find it a bit harder to read, but if anyone of you knows why they made this choice, I would be happy to know.
I tried to do this, but I got this error:
Invalid CSS after "... element(input)": expected "}", was ","
I use this to solve my problem.
Could the mixin accept multiple parameters for styling more than one element ?
I have my own way of structuring my SCSS and so far others I work with find it easy to understand/expand/maintain…but I have been looking at stuff like OOCSS, SMACSS, BEM etc.
It seems to me that this approach falls apart in a situation such as…
(Assuming Jade for markup)
Let’s say the
--disabled
class is applied byng-class
. If I want my icon/text to have different properties based on the button being--disabled
, I would need to do…Seems like more of an annoyance, or am I thinking of the wrong use-case here?
Good question. I generally solve this using an attribute selector like so:
Unfortunately, this will not work for HTML that has multiple classes (like
.btn.primary
), but I generally avoid that anyway, using one class to represent the thing, and Sass to determine the presentation layers.Following BEM conventions, you don’t need to specify the block modifier within the element. So
.button--disabled__icon
would not be considered valid BEM code.Instead, your nesting should look like this
And for this to work, the structure of the compiled CSS would be
This output can be achieved by updating the “unnecessary” mixins and make them aware of this use case. Now the mixins would actually become useful.
With Sass 3.4, string functions can be performed on the
&
selector.This is very exciting, since within the
modifier()
andelement
mixins we would be able to1. create a function that checks if the parent selector has a modifier already
2. compute the class names accordingly
To detail, if we have this type of input
The
element('icon')
mixin would check if the parent selector (&) contains a modifier already and output.block--modifier .block__element
, otherwise just outputblock__element
.I love the use of these mixins for generating BEM code but
How would I go about getting rid of the last link’s
:after
?I can’t:
The idea behind the BEM methodology is to strip any logic into small pieces, so everything becomes a lot more maintainable. I would assume the ‘breadcrumb’ in your code is a block, while item and link are elements.
Indeed, nesting an element inside an element shouldn’t work (because it breaks the very basic BEM rules). But you could make it work by turning the item into a block and build a block-element-modifier object out of it.
So you would keep the current structure up to the item, then inside create a breadcrumb-item block, where you define your advanced link logic
Then in the html you could use this new BEM block to complement the logic of the initial element
How is this helpful? You’ve now separated the logic into a smaller BEM module and split responsibilities as well.
The item element
.breadcrumb__item
handles the float, the item block.breadcrumb-item
handles the link and the separator logic.If you’ll add more complexity to the link, like an icon or a highlighted modifier, you’re going to do it a lot easier by changing only this small structure.
I dont think the
will work though – the
e
mixin is going to try to add it’s__link
selector on top of the&:not(:last-child)
which would result in something like this:see this gist. Unless my
e
mixin is incorrect.Actually, I just figured out a workaround – see this gist. The key was to take the
&
parent selector on thee
mixin and scan it for psuedo selectors. if they existed, slice them out.That’s right Danny, the element mixin should be a bit more complex than the one provided in the example. It’s not enough to just checking if the selector contains a pseudo-selector, you also need to consider if the parent contains a modifier or not, to generate classes like
.block--modifier .element
, instead of.block--modifier__element
– which is not valid BEM.Your gist should be working just fine.
I’m using a set of custom mixins that cover more use cases, maybe I can write a short introduction and post the link here, if you think it could be helpful.
Good call! Yeah I’d like to see what you’ve come up with to get to the block/element from a parent selector. I opened this issue on a library that looks promising. It would be nice to see a community driven standalone library of BEM-related mixins.
Here’s a blog post describing some more use cases and a set of advanced mixins that help create modular and maintainable BEM structures.
https://m.alphasights.com/how-we-use-bem-to-modularise-our-css-82a0c39463b0#.o4tc7cevq
sderhbr rfvjui o
I still think it’s too bad that the starts-with (wildcard) selector doesn’t work with nested ampersands (and yes, I do understand the logic why this doesn’t work, just sayin’). This would eliminate the need for a double block selector. So instead of using
<div class="tile tile--disabled">
it would be possible to just write<div class="tile--disabled">
while still being able to style the tile and a disabled version in the same 1 level deep nesting block. This would result in losing 1 level of specificity in scss (which could be quite useful):This is an interesting idea indeed, you can create a mixin that could receive the wildcard match class name and return the wildcard + modifier (haven’t given it too much thought, but it’s doable, I’m sure).
Another thing you could do if you really hate the standard BEM convention is to have the block properties in a placeholder, then extend those on all modifiers.
It might look like this
This is one way to do it without having to duplicate the generated CSS properties.
But the whole point of the modifier is to extend styles of an element or a block. I find it really useful to call
class="
block__title
block__title--highlighted
block__title--with-icon
but in the end it’s just a matter of conventions.
Very nice. Your approach inspired me to attack a readability problem I’ve always had with Sass + BEM: combining multiple modifiers.
I extended your mixin to take multiple parameters:
This makes Sass code like this…
…generate the following CSS:
If you’re interested, I’ve expanded the mixins idea a bit since this post
https://github.com/alphasights/paint/blob/develop/styles/tools/_bem.scss
there is also a test to show some possible use cases
https://github.com/alphasights/paint/blob/develop/test/tools/_bem.scss
I personally couldn’t find a strong reason so far to combine modifiers, for example in your case I would just name the modifier
warning-inverted
, but it definitely looks like a good solution.Let me know if you find it helpful :)
wouldn’t the longer class names bloat the HTML markups?