What is the correct way of naming items in a list when the item itself has subcomponents. Is it the case that the item should be classed both as a child block of the list and as its own component? Is the following example correct?
<div class="news-feed">
<h3 class="news-feed__title">…</h3>
<ul class="news-feed__list">
<li class="news-feed__list-item news-feed-list-item">
<h4 class="news-feed-list-item__title">…</h4>
<img class="news-feed-list-item__thumbnail">
</li>
<ul>
</div>
@Undistraction
That's not a requirement but for sure valid way to handle such situations. Mix will help to split implementation between logical parts. E.g.
news-feed__list-item
will know about geometry (position, margin, etc.) andnews-feed-list-item
just about its internal things to make it reusable even withoutnews-feed
parent.Great. Thanks for your answer.
I have some notes that are worth considering:
With this structure, you shouldn't ever have
news-feed__list-item
outside ofnews-feed__list
. To declare that,item
should be a child oflist
:For this example, consider that starting a new block (
news-feed-list-item
) might introduce this block in an alternative context.<li class="news-feed-list-item">...</li>
doesn't exactly stand on its own, so you'd end up changing the wrapping element to maybe an<article>
This still doesn't stand on its own very well due to the naming, so consider the semantics of your outer block.
news-feed
is a feed of news, so why not just introduce news blocks within eachnews-feed__list__item
?Of course, you could choose to forgo the
<article>
wrapper:You might then go further to realize that the
news-feed
structure is pretty reusable, and you want to use it to list events as well, so consider just naming it a feed:@zzzzBov Thanks, but I think you're breaking with BEM conventions by referencing a grandchild in your class name.
@zzzzBov Hi, Timothy!
BEM methodology doesn't recommend to use elements within elements in class names. You don't need to resemble DOM structure in naming. Having one level structure makes refactoring much easier.
@tadatuta,
Yes, I understand that children within children in a BEM block should be avoided as much as possible, however that doesn't mean you should never have grandchildren. You should always have a compelling reason to use a grandchild element, otherwise it's likely that you should be composing nested blocks.
For
If you're willing to imply that
news-feed__list-item
may be used outside ofnews-feed__list
, then absolutely go ahead and skip on the grand-child element. However, if you need to explicitly require that the__item
is contained in the__list
, use grandchild elements.The purpose of that recommendation is to avoid crazy classes like:
This example makes it clear that there should be a
form
block with a__fields
element, and should compose afield
block with an__input
element.For what its worth, I think this highlights the biggest problem when it comes to BEM naming conventions - the lack of examples. I appreciate that BEM is much more than the naming, but there are a large number of people who have taken the naming conventions and are using them independently (or variations thereof - SUIT, BEMIT etc). It's really hard to find examples of basic patterns using BEM naming conventions - lists, tables, forms etc. Almost every article uses either Buttons or the Media Object and avoid the nuances.
I think the single most useful resource for those wanting to understand BEM naming conventions would be a series of html / CSS examples showing how BEM naming should be used, starting with basic elements and moving up to more complex relationships (structurally and in terms of variants).
@zzzzBov As there's no need for any special hint when dealing with
<tr>
and<td>
which should be inside<table>
or for<li>
to be inside<ul>
you actually don't need such hints for elements as well. DOM tree is quite enough for that.@Undistraction You are right. We're started the huge work on rewriting the whole documentation on https://bem.info from scratch with examples and already published some new articles in Russian. So translations are coming soon. While it's still WIP, we'll be happy to answer any questions here on the forum.
@tadatuta Let's ignore the
ul
andli
elements for a second and focus on the BEM classes that are being used (pretend everything is<div>
)If your styles would break when you write
without a
.news-feed__list
then you should absolutely restrict the item to be within the list.If you don't care whether the
news-feed__list-item
is within the list or not, then leave the classes as they are.Another consideration is whether you need
list-item
at all. BEM on atable
often jumps from the table to the cells, because no additional effort is needed for thetbody
,thead
ortr
elements.The original markup could have as easily been written as:
It seems like the point you're making is that the BEM classes don't need to match the DOM, which is absolutely 100% correct. The point I'm trying to make is that the DOM must match the BEM classes.
You should never have a child element outside of its parent block or element.
This is OK
This is NOT
The point I'm getting at is the
block__element
and__element__element
relationship establishes a hierarchical contract that must be respected by the DOM and makes it easier to spot errors in other developers' code.@zzzzBov That all makes perfect sense for the moment of the first introduction of such nested element. But then new requirements appear and refactoring of DOM ends up with refactoring of CSS as well.
And there's one more thing: we strongly believe that DOM tree should be auto generated from BEM tree and HTML representation of blocks and elements may be redefined with templates.
NBD, I use a preprocessor (LESS specifically, but whatever works):
If one of those elements has to move, or the name has to change, it's really easy to move everything around because it's all clustered. Again, you want to _avoid_ deeply nested BEM elements, as in SHOULD NOT use deeply nested BEM elements (rfc2119). That's not the same as never using them.
Good catch! :+1:
Still using nested elements is pointless. If you can't avoid it then you probably doing it wrong. If your tree becomes bigger — better to move this substructure to separate simple block instead of nesting.
Returning to your case, we usually doing it like that:
Different cases — different solutions, but never nested elements. :smirk_cat:
Oh, one more thing.
Personally we have about 400 blocks atm and going to rework them one by one. We started with documentation and templates (btw, these can help you to check your BEM tree structure, and better just templates). Then we go for deprecating old realizations and baking the new ones.
Our experience:
Since blocks must have transparent public API we can test them easily. Instead of extending better to mix blocks (not sure why mixes works like a charm here).
And also, if its possible for you (you have build system that supports deps resolving, merging files, freeze/prepare urls for static resources):
Hope it helps ;-)