Expressive BEM with Sass: a different approach
Disclaimer: This is just a thought about a different approach. I am by no means saying that this approach is better than anything else. :)
At first, I was intending to write some long-drawn blog post about how you can use a few Sass mixins to create a vocabulary abstraction that would allow a different, possibly more expressive way of writing BEM-classes. Instead, here's the short-form.
Update: I've updated the mixins, you can view them here.
If you didn't know already, you can write BEM in .sass (not .scss, sorry), like this:
// import 'expressive mixins' from /andersschmidt/pen/MYZqar
// Example A: The classic media object
+new (media, object)
+has (image)
+when (reversed)
+has (body)
// Example B: The person OOP example from CSS Wizardry
+new (person)
+has (hand)
+when (left)
+when (right)
+if-its (open)
+holds (ring)
+when (female)
+has (hand)
// Example C: The puppet, using more classic OOP,
// thanks to @zerratar for an awesome way of explaining OOP
// in terms of puppets and puppetmasters
+new (puppet)
+has (head)
+has (face)
+has (arm)
+when (left)
+when (right)
+has (leg)
+when (left)
+when (right)
+when (wooden)
+has (foot)
// Example D: Menu with menu items that can have a dropdown
+new (menu, component)
+has (item)
+when (active)
+holds (dropdown)
// Example E: Modal with title, gallery modifier and open state
+new (modal, component)
+has (title)
+when (gallery)
+if-its (open) // translates to is-open
Which produces this CSS:
.media-object {
/* */
}
.media-object__image {
/* */
}
.media-object__image--reversed {
/* */
}
.media-object__body {
/* */
}
.person {
/* */
}
.person__hand {
/* */
}
.person__hand--left {
/* */
}
.person__hand--right {
/* */
}
.person__hand.is-open {
/* */
}
.person__hand.holds-ring {
/* */
}
.person--female {
/* */
}
.person--female__hand {
/* */
}
.puppet {
/* */
}
.puppet__head {
/* */
}
.puppet__face {
/* */
}
.puppet__arm {
/* */
}
.puppet__arm--left {
/* */
}
.puppet__arm--right {
/* */
}
.puppet__leg {
/* */
}
.puppet__leg--left {
/* */
}
.puppet__leg--right {
/* */
}
.puppet__leg--wooden {
/* */
}
.puppet__foot {
/* */
}
.menu-component {
/* */
}
.menu-component__item {
/* */
}
.menu-component__item--active {
/* */
}
.menu-component__item.holds-dropdown {
/* */
}
.modal-component {
/* */
}
.modal-component__title {
/* */
}
.modal-component--gallery {
/* */
}
.modal-component.is-open {
/* */
}
If you have these .sass mixins classes:
// --------------------------------------------------
// Vocabulary mixins (for BEM and namespacing)
//---------------------------------------------------
=new ($name, $type: null)
@at-root
@if $type != null
.#{$name}-#{$type}
/**/
@content
@else
.#{$name}
/**/
@content
=if-its ($state)
&.is-#{$state}
/**/
@content
=holds ($something)
&.holds-#{$something}
/**/
@content
=has ($name)
@at-root
#{&}__#{$name}
/**/
@content
=when ($name)
@at-root
#{&}--#{$name}
/**/
@content
It's just a different way of writing the same thing. I don't know if I particularly love this approach, but when I'm writing my CSS in this way it feels strangely "in tune" with my own mental model.
Stay sharp!