Leveraging the CSS sibling selector within BEM

Viewed 40

Say I have a block called .my-block. Depending on whether a specific element, say, .my-header appears before it, I need to style it differently. Because this is easy to do with the CSS sibling selector, I'd like to avoid adding conditionals to my HTML templates and add modifiers to my-block. I've considering two options.

Option 1)

<body class="my-block-container">
  <header class="my-header my-block-container__header"></header>
  <div class="my-block-container__my-block"</div>
</body>

Option 2)

  <header class="my-block-sibling"></header>
  <div class="my-block"</div>

I dislike option 1, because no classes will be applied directly to .my-block-container and .my-block-container__header. Moreover, I'd have to either rename the children of .my-block and apply the somewhat vague my-block-container as a block name, or introduce a new block-level name with the only purpose of selecting a sibling.

I dislike option 2, because it's not truly BEM; there's no true block-level name.

Should I accept that I've reached the limits of BEM naming, or is there a convention for this kind of situation?

2 Answers

Did you considered using a modifier for this case?

<body>
  <header class="my-header"></header>
  <div class="my-block my-block--after-a-header"</div>
</body>

This will allow us to have separated styles between header and block, and to style differently a block when it's after a header.

Next step will be to rename the modifier class to express what it does (and not when to use it), so it will allow you to reuse it in an other context in the future. For example: .my-header--small will be more explicit than .my-block--after-a-header

I think your idea to use a sibling selector (+) is a good one in this scenario.

Here is a working example of BEM + sibling selector in practice,


Working Example:

.my-block-container {
  float: left;
  width: 120px;
  height: 144px;
  margin-right: 12px;
  text-align: center;
}

.my-block-container__header {
  line-height: 24px;
  font-weight: bold;
}

.my-block {
  width: 120px;
  height: 120px;
  line-height: 60px;
  color: rgb(255, 255, 255);
}

.my-block-container__my-block {
  margin-top: 24px;
  background-color: rgb(255, 0, 0);
}

.my-block-container__header + .my-block-container__my-block {
  margin-top: 0;
  background-color: rgb(0, 0, 255);
}
<div class="my-block-container">
  <div class="my-block my-block-container__my-block">Not preceded by &lt;header&gt;</div>
</div>

<div class="my-block-container">
  <header class="my-block-container__header">Header</header>
  <div class="my-block my-block-container__my-block">Preceded by &lt;header&gt;</div>
</div>

Related