monterail / guidelines

[DEPRECATED] We are Ruby on Rails experts from Poland. Think hussars. Solid & winged. These are our guidelines.
71 stars 17 forks source link

Writing css and html in accordance to BEM #151

Closed sheerun closed 11 years ago

sheerun commented 11 years ago

I suggest every frontend developer read http://bem.infoc and wrote html / css in accordance to this standard.

Here is argumentation:

We should probably agree on block's element separator.

One possible set of rules is:

.block{}
.block__element{}
.block--modifier{}

@jandudulski, @porada, @venticco, @michlask, @tallica

jandudulski commented 11 years ago

I think @porada already use this style

sheerun commented 11 years ago

I'm not sure if we should use .block--modifier instead of .block.block_modifier. Any reasons @porada ?

But you can use any other separators for it. E.g.: block-name--element-name or blockName-elementName

Personally I'd like to use:

.block {}
.block-element {}
.block.block_modifier {}
sheerun commented 11 years ago

Or why not use nouns as block names and verbs as modifier names:

.block {}
.block-element {}
.block.modified {}

eventually:

.block {}
.block-element {}
.block.is-modified {}

I really don't like

.block--modified {}
porada commented 11 years ago

Modifiers: why .block--modified is better than .block.modified or any of its variations

One of the key aspects of OOCSS is selector performance. Apart from the fact that .modified or any adjective used a modifier class name is ambiguous and can be used stylesheet-widely (which is really not recommended), .block--modified is faster than .block.modified.

Elements and submodules: why .block__element over .block-element or any of its variations

.module-element (with a single dash) isn’t an optimal choice of naming classes, because a module name may consist of several words, like .search-form. Then, .search-form-field doesn’t provide as much information to other people working on the project as it should. Even though it looks much better, you can’t really say whether it’s a form-field from the search module or it’s the field that’s the part of search-form.

I’ve been trying to develop a decent naming pattern for quite some time. Most recently I used .ModuleName-element, which doesn’t send a clear message at first sight when it comes to .ModuleName-SubmoduleName-element (and sometimes you do need those).

The more conventions I try, I always come back to .module-name__element, because it’s the one that’s really clear even just by looking at it. BTW, I didn’t like how it looks like at first, big time.

Why extending isn’t a good idea: why using .block.block--modified in markup is better even though it takes more time to write

In our recent project, the Facebook app, I embraced the pattern of @extending .block--modified with .block and have come across the following issues:

Multiple modifiers

.thread__comment--modified--just-added--featured--level-2? The length isn’t the main issue here. In fact, .thread__comment.thread__comment--modified.thread__comment--just-added↵ .thread__comment--featured.thread__comment--level-2 takes up much, much more space. But the true devil lies within your stylesheets, because you’d have to consider all cases:

.thread__comment--just-added {
  @extend .thread__comment;
}

.thread__comment--modified {
  @extend .thread__comment;
}

// …

.thread__comment--modified--just-added {
  @extend .thread__comment--modified;
  @extend .thread__comment--just-added;
}

.thread__comment--just-added--modified {
  @extend .thread__comment--modified--just-added;
}

// …

In this case (4 modifiers), there are 4! = 24 cases to consider. Unless you force alphabetic order (which creates another level of confusion), you have to consider the order of modifiers too.

Scripting

Imagine that your .thread__comment--modified--featured isn’t featured anymore. In the SPA world (and not only), you probably just remove the class name, but you can’t do it in the simple way like the following:

// Using `this` for the sake of simplicity
$(this).removeClass('thread__comment--featured');

// You need to *rewrite* the class name
$(this).removeClass('.thread__comment--modified--featured')
  .addClass('.thread__comment--modified');
    // I do hope you properly parsed the class name before doing stuff

And, given the following elements, good luck finding all modified comments:

<article class="thread__comment--just-added"></article>
<article class="thread__comment--just-added"></article>
<article class="thread__comment--just-added--modified"></article>
$('thread__comment--modified').length; //→ 0
Lenghty lists of selectors over time

In the Facebook app I mentioned, we used several states of action buttons (normal, main, disabled, block, major to name a few). Thanks to the heavily-@extended codebase, you can’t find a definition of a basic button that consists of less than 10 selectors. Should one of them break (e.g. due to an unsupported vendor-prefixed pseudo-class or pseudo-element), all of them get skipped by the rendering engine.


tl;dr version: the more you front and end, the more you realize that BEM is the pattern to use.

porada commented 11 years ago

cc @venticco

jandudulski commented 11 years ago

Nice. Codetunes that @porada !

venticco commented 11 years ago

:+1:

sheerun commented 11 years ago

I like more search_form-field, than search-form__field

venticco commented 11 years ago

I like more search-form__field than search_form-field.

teamon commented 11 years ago

For rails apps search_form-field could make sense, in ruby _ is part of an identifier, - is not.

porada commented 11 years ago

But we’re talking about CSS. :wink:

When looking at search-form__field, I immediately see search-form and its field. In case of search_form-field, it looks to me more like search and form-field. Selectors in CSS that consist of multiple words had always been concatenated using a single dash. What BEM does is introducing __ (and --) to improve selector semantics without changing the already established conventions. Don’t overthink it, guys.

jandudulski commented 11 years ago

Agree with @porada

porada commented 11 years ago

:+1: