11

SO I have a problem with OOCSS. It is supposed to be more portable but compared to how I usually do things, I'm finding it less so.

My example:

I have a widget testimonial. In the main content body (which has a white background) the testimonial has a black font. But in the footer (which has a blue background) the testimonial needs a white font.

Before OOCSS, I would do something like this:

#main-content .testominial {
  color: #000000;
}
#footer .testominial {
  color: #FFFFFF;
}

With this "old" approach, I could drag my widget from the content area to the footer and the colours would simply work - I wouldn't need to change my CSS or DOM classes of the widget.

With the new OOCSS/BEM, I am NOT supposed to couple the .testimonial class to the ID (or to the location), but rather I should subclass it like so:

.testominial {
  color: #000000;
}
.testominial--footer {
  color: #FFFFFF;
}

The problem with this is that I can no longer drag my testimonial from the content area to the footer without going into the DOM and changing the classes on the testimonial widget - It is LESS portable as it requires manual intervention by a developer; whereas before an editor could just drag it and the styling was automatic.

Am I missing something? There seems to be no solid real-world examples out there?

kangax
  • 38,898
  • 13
  • 99
  • 135
gjok
  • 195
  • 1
  • 12
  • Yeah, this is kind of why I have no truck with these patterns, They basically go against the grain of how CSS selectors are designed to work. – Alohci May 28 '15 at 09:24
  • imo, the purpose of BEM/OOCSS is to prevent 'uintended consequences' of making a change in one 'component' and having the display 'break' somewhere else. It does this by 'limiting' the CSS 'cascade' by class names. The fact that this helps re-use is a bonus. It certainly helps maintenance. It also makes it easier to reason what the CSS does and what it will affect, I am a programmer rather than a designer and not a CSS expert. – Ryan Vincent May 28 '15 at 10:10
  • @RyanVincent Reuse is not just a bonus. It is a strong argument of Nicole Sullivan in [Our best practices are killing us](http://www.slideshare.net/stubbornella/our-best-practices-are-killing-us) (OOCSS). And, BEM is a "Technology for creating web applications", BEM helps to make code factorisation, that is reuse. – Paleo May 28 '15 at 10:25
  • @Tarh, point taken - i did suspect that adding the 're-use' line worded that way, to my comment, was a mistake. I do use 'BEM' and it has made using CSS almost enjoyable. It is certainly more predictable. :) – Ryan Vincent May 28 '15 at 10:46
  • In retrospect I should have put more emphasis on OOCSS rather than BEM. I am just trying to figure out how I can reuse a widget to look different depending on its parent container without a) the user adding any classes or code, and b) using Nicole Sulivans concepts – gjok Jun 01 '15 at 14:53

2 Answers2

5

You need to consider dropping the testimonial naming as well as the footer.

Consider this example:

.primary-box { }
.primary-box--reduced { }
.primary-box--standout { }

In the example the classes are completely independent of their page context. The result is that the classes are completely re-usable. Any box on the page can take the classes above and expect to be styled exactly as defined.

For example, you could have:

<header>
    <div class='primary-box primary-box--reduced'></div>
</header>
<div class='content-box'>
    <p class='primary-box primary-box--standout'></p>
</div>
<footer>
    <div class='primary-box primary-box--reduced'></div>
</footer>

Now when the designer comes back and tweaks the padding of the standout boxes you can go directly to those styles and tweak them, confident that the only areas that will be effected will be the areas that have those classes in the HTML.

Also, when you decide to move .primary-box--reduced from the <header> into the menu bar that sits above it, or into the footer, you can be confident that the styles will come along, completely.

When you need another element somewhere, perhaps a primary-box--standout, or just a default primary-box in the header, you just create it and add the classes, they styles will follow completely.

You'll never inherit unexpected styles either.

This is very much a real world example, a site I built recently was almost all built like this, I say almost all because I'm still learning, but I can guarantee the bits I had the least trouble with on a fast-moving project with very fluid designs were the ones with non-specific context.

What's important is the lack of context. In the first example, .testimonial--footer is very context dependent, you really need to use it on testimonials in the footer only.

And as if by magic CSS Wizardry cover this exact topic

EDIT: I added this example to help with a comment made on my answer. This isn't BEM, or OOCSS, though it is a bit closer to the SMACSS approach. It's how I tackle problems with css and is a hybrid BEM / SMACSS approach:

Loaded in order:

  • module files, such as .primary-box
  • page section files, such as .header or .call-to-action
  • page files, such as .about-us or .contact

Each file gets more and more specific, while simultaneously building more complex and modules. Building on the examples above and hopefully helping the OP, you could see styles like:

.header {
  .primary-box {
    color: #000;
  }
}

which would over-ride the module styles using a more specific nested class notation. Please note, I would still avoid using a class name like .header - .banner-standout would be better as it's re-usable anywhere without confusion

Next, you could even see:

.about-us {
  .header {
    .primary-box {
      color: #f00;
    }
  }
}

I find this works very well in real projects for context while retaining the context free power of BEM, though I would also urge as much as possible to push up this chain into the modules. Life is easier if I recognise a new generic page section or module and re-organise the naming and files appropriately. In a project where the code has been refactored with care I have nothing in page files.

Toni Leigh
  • 4,830
  • 3
  • 22
  • 36
  • Thanks Toni, very nice to see further examples, but despite trying to make my question concise I think my main concern is still being missed. My point being that I do NEED my blocks to be context dependent. You say wherever I put my html the styles will come along, but that is what I dont want. In the footer the font colour needs to be white, but the main body it is needs to be black, so that there *is* a context dependency. Currently we drag widgets around the screen, and in the old approach (see my example) we didnt need to manually change classes to the widgets as the parent id managed it. – gjok Jul 09 '15 at 11:06
  • Take a look at the answer in this post: http://stackoverflow.com/questions/22566179/bem-block-naming-nesting it demonstrates a perfect example of the potability problem I am facing. If you were to move the 'nav' from the 'content' div to the 'sidebar' div, you would need to manually replace the 'nav--content' classes with 'nav--sidebar' for all the child elements. - This is what I menan by being not portable. thanks - please help. – gjok Jul 09 '15 at 11:18
  • @gjok - please see edit, I added a practical example that I have used that can allow for the power of BEM to be utilised in situations where context is important – Toni Leigh Jul 09 '15 at 11:31
  • Thank you. So this basically compiles to the format that I exemplified in my original post, right? Which means that basically its OK to use the footer context if the footer context is important - In other words BEM doesnt work for this sort of problem? Is that correct? – gjok Jul 09 '15 at 13:29
  • 1
    BEM doesn't really have a solution to this without doing `.box--footer` and `.box--header` which isn't really any different. – Toni Leigh Jul 09 '15 at 13:35
2

With this "old" approach I could drag my widget from the content area to the footer and the colours would simply work - I wouldn't need to change my CSS or DOM classes of the widget.

If you "drag" the element .testominial from the container .main-content to the container .main-footer, that is you change the DOM. So you can also update the modifier in the CSS classes, there is no additional cost.

The purpose of BEM is to make CSS classes reusable. The following modifiers can be reused in various environments.

CSS:

.testominial {
}
.testominial--darkFg {
    color: #000;
}
.testominial--lightFg {
    color: #FFF;
}

HTML:

<main class="main-content">
    <div class="testominial testominial--darkFg">...</div>
</main>
<footer class="main-footer">
    <div class="testominial testominial--lightFg">...</div>
</footer>

With the old approach, you'll have to change the CSS code each time you need a new block .testominial in a new container. HTML and CSS are strongly coupled, and some CSS code will be duplicated.

With the BEM approach, you'll have to add some CSS code each time the designer will add a new variation of the block appearance. HTML and CSS are less coupled, and CSS is better reused.

Paleo
  • 21,831
  • 4
  • 65
  • 76
  • So @Tarh, looking at your HTML snippet, you have MANUALLY to add classes "testominial--darkFg" or "testominial--lightFg" to the widget class list when you drag the widget around the page. Our users would not be able to do that. We need them to be able to drag and drop without coding. – gjok May 28 '15 at 10:50
  • If you do CSS right, HTML and CSS are totally uncoupled. Selectors provided the binding between the two worlds, and the cascade and specificity provides a rich binding language that is masked by BEM. – Alohci May 28 '15 at 11:17
  • 1
    @gjok Maybe BEM is not adapted to your use case? If your widget needs to adapt its appearance in function of the container, then you can't use a pure BEM methodology. By definition, in BEM, blocks are context free. – Paleo May 28 '15 at 12:27
  • 1
    I cant see any way around this other than using the "old approach". OOCSS tells us not to tie our modules to parent locations, and it also claims to make our components more reusable - but there is a major conflict here as the location usually defines the appearance, as in my example. How does OOCSS cater for this? – gjok May 28 '15 at 12:55
  • @gjok There is no conflict because your use case is not reuse. OOCSS and BEM allow reuse by making objects/blocks free of context. You need an object/block that adapts its appearance in function of the container. In other words, you need to apply a modifier automatically, depending of the parent container. You can do that by adding a CSS class (programmatically, with JavaScript) or using a CSS cascade (but not in a OOCSS/BEM way). – Paleo May 28 '15 at 14:16
  • In my projects, I often opt for a mixed solution. I use BEM as a general frame (with naming inspired from the OOCSS approach). And I have a differentiated syntax for use cases that do not fit in the BEM way. – Paleo May 28 '15 at 14:25
  • It is reuse; I want to "reuse" my widget in the sidebar, the footer, or wherever without duplicating my code. Nicole Sulivan and a hundred other people blog about this but none of them explain how its done.How do I get my footer testimonial to show a white font unless I use a descendant selector of the footer (#footer .testimonial {}) Sorry but I'm not getting it. – gjok May 28 '15 at 15:01
  • 1
    Having "dark" and "light" inside your class names is a sign that your class names are inline styles masquerading as well factored layout. – recursive Jun 30 '15 at 21:33
  • 1
    @recursive I get that - Obviously I would never use colour names, but they will always be dark or light - that is the requirement. If its set in stone forever then its not a problem. – gjok Jul 23 '15 at 11:11