Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Positioning a block with a modifier? #68

Open
mindplay-dk opened this issue Feb 7, 2018 · 5 comments
Open

Positioning a block with a modifier? #68

mindplay-dk opened this issue Feb 7, 2018 · 5 comments

Comments

@mindplay-dk
Copy link

Is any BEM entity allowed to modify any other entity?

Specifically, is an element allowed to modify another entity?

Consider the following example, where a modifier positions another block - in this case, we have a close block for close gadgets on dialogs etc. and a modal block for modal dialogs:

<div class="modal">
  <header class="modal__header">
     Title goes here...
     <span class="close"></span>
  </header>
  <section class="modal__body">
    Content goes here...
  </section>
</div>

The close block itself doesn't have margin/padding/positioning, because we want it to be reusable in different contexts.

In the context of a modal, the close gadget needs to be positioned properly though, and normally I'd just do this:

.modal__header .close {
  position: absolute;
  right: 7px;
  top: 4px;
}

I've been told this goes against BEM, and instead I should add a modal__close element, and mark it up as:

<div class="modal">
  <header class="modal__header">
     Title goes here...
     <span class="close modal__close"></span>
  </header>
  <section class="modal__body">
    Content goes here...
  </section>
</div>

My argument is that the close modal__close combination is meaningless, because:

  1. The modal__close element doesn't work on it's own
  2. If you forget to add modal__close, the close gadget will break the design.
  3. The close block should always and only occur precisely once in a modal__header.

In other words, the close modal__close combination is meaningless since, in the context of a modal, there is no use-case for either close or modal__close without the other.

I'm struggling to understand precisely what BEM is - if it's a naming convention and a set of patterns, the way I understand patterns (as a programmer) is as language used to describe what you've implemented; but not as decision-making drivers that should dictate what you implement.

In the same sense, I feel that BEM naming is valuable as a convention for describing the logical relationships between CSS classes - and shouldn't be viewed as a set of rules that dictate how you structure your CSS.

In fact, for this modal example, I'd like to go even simpler and drop the modal elements:

<div class="modal">
  <header>
     Title goes here...
     <span class="close modal__close"></span>
  </header>
  <section>
    Content goes here...
  </section>
</div>

And just write CSS like this:

.modal > header {
  ...
}

.modal > section {
  ...
}

Again, my argument is that the immediate header and section elements of a .modal are clearly already elements in the HTML sense, and there is no other use-case for header or section elements as immediately children of a .modal except as the header and body elements of that modal.

Overriding these with a modifier, despite the higher specificity, is literally almost the same thing - e.g. this:

.modal--large > header { ... }

Versus this:

.modal--large .modal--header { ... }

I don't understand how either of these is any better or worse, beside the specificity argument, which seems inconsequential here, since you'll need to specify the modifier and target the header element somehow, for any rule that affects anything below it.

In fact, the first option seems like a generally safer choice in a lot of cases, such as, for example, panels within panels:

<div class="panel panel--red">
  <header>...</header>
  <section>
    Some content here, and another panel:
    <div class="panel">
      ...
    </div>
  </section>
</div>

In this example, I'd like to target .panel--red > section to make it red - and this won't and should not affect the color of the nested panel inside it.

Contrast this with:

<div class="panel panel--red">
  <header class="panel__header">...</header>
  <section class="panel__body">
    Some content here, and another panel:
    <div class="panel">
      ...
    </div>
  </section>
</div>

If you target the panel body with a selector like .panel--red .panel__body to affect the color, this will cascade to any nested panel__body elements and override their default color, which is not what was intended.

Bottom line: should you think for yourself and implement your CSS as needed - or should you apply BEM patterns slavishly and set aside your own judgment?

Do my examples go against BEM in any way?

@mindplay-dk
Copy link
Author

@zxqfox I'd love it if you or someone else at Yandex could provide an authorative answer to this ;-)

@tadatuta
Copy link
Member

tadatuta commented Feb 7, 2018

@mindplay-dk Of course you should always think and decide for yourself.

But at the same time BEM as methodology is a collection of best practices which work just fine on a large number of different projects and proved to be really great.

Getting back to your question. I think almost all the questions you asked are answered on https://en.bem.info/methodology/css/

As for question about .modal--large > header { ... } versus .modal--large .modal--header { ... } there's a third option: .modal--large > .modal--header { ... }

@qfox
Copy link

qfox commented Feb 7, 2018

Hello.

My argument is that the close modal__close combination is meaningless, because:

  1. The modal__close element doesn't work on it's own

Not sure what it means. modal__close define the relation between modal container and close container: even your styles says this: position: absolute, left, top.

The possible reason we should mark it with element is making modal and close blocks less related to themselves. E.g. when we want to use close in the other place.

I guess this topic is literally about amount of connections between components https://en.wikipedia.org/wiki/Strongly_connected_component

It works even in Linux kernel. Each component should be separated. If it has a lot of connections with another components — then these components are strongly connected and works as one monolith.

Same with mixed selectors: .component1 .component2 { ...styles... } — this is a bad practice should be replaced with .component1__semantic-thing or .component2--modified-for-component1

  1. If you forget to add modal__close, the close gadget will break the design.

It will break the design of modal but not the close component. And it's fine.

  1. The close block should always and only occur precisely once in a modal__header.

Actually, this means you should make it an element of modal and don't need the separate close block.
It's totally valid to have structure like: .modal > .modal__header > .modal__close.

.modal > header {
  ...

Modal is a good example why we should not use header tag in selectors.

Any user generated content with this tag will break the design. .modal here works as a namespace and if you don't like this prefix you can take a look at CSS Modules or something similar.

Agree with @tadatuta that you can use > and other CSS Next feature if need.
And I believe it should be .modal__header ;-)

@mindplay-dk
Copy link
Author

The modal__close element doesn't work on it's own

Not sure what it means

Just that it's meaningless on it's own - it doesn't work without close.

The close block should always and only occur precisely once in a modal__header.

Actually, this means you should make it an element of modal and don't need the separate close block

What I meant is, there would be no reason to use a close block anywhere else within a modal - the only expected use is in the header, and it's easy to target that precisely with .modal__header > .close without adding another class.

if you don't like this prefix you can take a look at CSS Modules or something similar.

I have no problem with the naming conventions - my problem is the meaningless verbosity that ensues for a case like this when applying unnecessary patterns slavishly.

It seems that anytime I bring up practical, concrete points, these are dismissed in favor of some theoretical "best practice" or pattern (or some interpretation of either or a combination of those) that provides no additional practical value in the concrete case.

What I'm struggling to discern is whether following BEM naming conventions is enough to say that "we're using BEM".

In other words, what is "BEM" precisely? By the looks of it, it's a naming convention, and a set of patterns, and a big framework comprising many packages for building BEM-compliant components and applications.

People say "BEM", and they apparently mean very different things - many seem to just apply the naming convention, and claim that makes it BEM, even if they follow the patterns and practices only losely or not at all.

The "Methodology" pages talk about file system structures and build systems, scripting conventions, etc. - which makes it very hard to draw the line and explain what exactly we mean by "BEM".

Thus far, every person I've met has entirely their own perception of the scope of "BEM", ranging anywhere between "just a naming convention", up to "apply all of these patterns mechanically".

There is already a lot of disagreement in a team of 3, and if we decide to ask a team of 20 to apply all or part of these conventions, patterns and practices, we have to be extremely clear on what precisely we mean by "BEM".

It's confusing to the point where I'd almost rather recommend we use the BEM naming convention and nothing else, as I'm afraid that 20 people struggling for concensus internally isn't going to help productivity at all.

@qfox
Copy link

qfox commented Feb 8, 2018

What I meant is, there would be no reason to use a close block anywhere else within a modal - the only expected use is in the header, and it's easy to target that precisely with .modal__header > .close without adding another class.

Oh, right, but even in this case single .modal__close class will work much faster. It's usually important for big projects with a lot of client logic and styles.

What I'm struggling to discern is whether following BEM naming conventions is enough to say that "we're using BEM".

As for me BEM is a set of good practices based on experience.
By using subset of them in each project I'm using it. Even if some of practice does not work in some project I still using the rest. So yes, I still do it.

In other words, what is "BEM" precisely? By the looks of it, it's a naming convention, and a set of patterns, and a big framework comprising many packages for building BEM-compliant components and applications.

Well, it's hard to say but I guess I can't say more than "Methodology for Web-development" blabla... bla. I don't know a good definition for now.

People say "BEM", and they apparently mean very different things - many seem to just apply the naming convention, and claim that makes it BEM, even if they follow the patterns and practices only losely or not at all.

Yes, I'm strongly agree that this is an important thing and it's breaking the growth.
We even tried to split it to BEM Platfrom, BEM Fullstack, BEM Methodology, BEM Frameworks, but if you talking about it now then it's still a problem.

Also there is problem that English-community thinking that BEM is a CSS-related Methodology.
I'm just opening BEM page on the Wikipedia and see redirect to CSS there.

And we should accept that the most part of People talks about CSS when pronouncing BEM. It's sad, actually.

The "Methodology" pages talk about file system structures and build systems, scripting conventions, etc. - which makes it very hard to draw the line and explain what exactly we mean by "BEM".

Thus far, every person I've met has entirely their own perception of the scope of "BEM", ranging anywhere between "just a naming convention", up to "apply all of these patterns mechanically".

Even monorepos are very close architecturally to Compoments based on BEM https://github.com/babel/babel/tree/master/packages/: each components placed in separate directory with a bunch of tests and a readme file.
But people won't see this if no one says.

There is already a lot of disagreement in a team of 3, and if we decide to ask a team of 20 to apply all or part of these conventions, patterns and practices, we have to be extremely clear on what precisely we mean by "BEM".

It's confusing to the point where I'd almost rather recommend we use the BEM naming convention and nothing else, as ...

Would be great if you have done this and will share the results. Very interesting, actually.

The most interesting thing is argumentation on these points:

  • File structure — monorepos are pretty popular now, and it's nice to place tests about the code)
  • Dynamic components — even if you linking them with render method (like in any VDOM realisation) it's great when names of components in JS are equal to CSS "namespaces" (blocks in BEM)
  • Relations between components (including business logic) — if one components depends on another there should be relation. If you have 100+ components with random relations (random graph of dependencies) would be great to test them selectively (test only affected ones).

If you had hot discussions on another BEM practices — please tell about it too.

I'm afraid that 20 people struggling for concensus internally isn't going to help productivity at all.

I think I can say that we have a internal block library named Lego (because of blocks-bricks) and earlier it was a seasonal fun Lego-flame/blame where we talk a lot in a huge auditory about BEM and how to use it well. For now almost everyone knows how to use elements, modifiers, when to use it, when do not, how to place it on file system and why, etc, etc.

But you are right that it will be hard to teach everyone to use all aspects of BEM properly.
It will spend a lot of time and nerves to find compromise between theory, practical implementation, and probably personal feelings.
But it is worth it for sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants