📜 ⬆️ ⬇️

BEM Methodology on the example of stickers in opencart



Since I prefer the BEM methodology, having started working with opencart, I immediately faced terrible things for me, these are nested selectors. They are everywhere! Starting from the default template, ending with almost all modules and authoring templates. Why is that? I think there are a number of reasons:

  1. Opencart is built by default on nested selectors, both template and admin panel.
  2. Most developers who work with opencart are exactly back-end developers, they just picked up this approach.
  3. There are a number of necessary classes and id to which both standard opencart functionality and author modules are attached, and all the same back-end developers, and their followers, for various reasons simply do not want to change anything and go with the flow.

I don’t want to say anything bad about back-end developers, but many of them are really weak in the front-end and even in the layout. This opinion was formed on the basis of communication with them, teamwork and, in general, their activity on the opencart thematic forums. I emphasize what I mean exactly the niche of opencart developers.
')
I make templates from scratch according to the BEM methodology (as far as it is possible within the framework of opencart) and I can say with confidence that any module starts from a half kick, regardless of the markup. The module, which will be discussed below, does not need any revisions at all, all that is needed is to simplify work with it and to implement the opportunity to reuse it in other projects. I took this module as an example, as it is very simple and there is no need to be distracted by a bunch of extra code, but at the same time it contains all the problems that BEM solves. This is a real-life module and there are a lot of such modules, and just templates. I believe that one combat example is better than hundreds of abstract ones.

To begin, I will describe the essence of the problem . A sticker module is built into one of the domestic opencart assemblies. It displays the selected sticker at the specified angle:
Upper left / Upper right / Bottom left / Bottom right
Options for stickers without restrictions, but a maximum of 4 positions:



Now look at the markup and styles:



What we see:

  1. All stickers are embedded in the image block.
  2. Despite the fact that the image block by logic is designed to store the image of the goods, all the styles of stickers are tied to it, and now we will look at the whole css and especially the nesting in the last lines:

/*sticker*/ .image { position: relative; } .image .corner_0, .image .corner_1, .image .corner_2, .image .corner_3 { height: 57px; width: 58px; position: absolute; z-index: 998; } .image .corner_0 { left: 0px; top: 0px; } .image .corner_1 { right: 0px; top: 0px; } .image .corner_2 { left: 0px; bottom: 0px; } .image .corner_3 { right: 0px; bottom: 0px; } .box-product .image .corner_0 img, .box-product .image .corner_1 img, .box-product .image .corner_2 img, .box-product .image .corner_3 img { border: none; padding: 0px; } .box .box-product .image .corner_0 img, .box .box-product .image .corner_1 img, .box .box-product .image .corner_2 img, .box .box-product .image .corner_3 img { width: 60%; } 

If .image .corner_2 looked even less acceptable, then .box .box-product .image .corner_2 img already looks not so optimistic ... In general, you can guess that somewhere we will have .box-product without a parent .box and some styles are applied, and somewhere with the parent there are others, but here a number of problems pop up before us:

  1. If the stickers are moved out of the limits of .image , all the styles will fall off, and if we take .image with us and put it in another place, then apply the .image styles where they are not needed.
  2. If we suddenly rename image, which logically is not a repository for stickers or .box or .box-product, which are even higher and certainly do not mean that the stickers are tied to them, in any of these cases we will not get the expected result .
  3. What if we want to put .image on the same level as the .box-product ? Again something goes wrong ...
  4. There are many duplicate selectors in which only .corner_ # changes, and if we suddenly change this nesting or want to transfer the code to another template, we will have to change it everywhere, and there may still be media queries, this is just a waste of time.
  5. Increased specificity. This problem always becomes noticeable after a while and often rests on the shoulders of those who did not create it ...

Those who are familiar with the BEM methodology have long been aware of this, and those who are not familiar, I think, have repeatedly encountered. Let's try to solve these problems.

Since one of the main tasks is the ability to reuse the code, we cannot name our corner stickers as before, because perhaps in another project we want them to be not in the corners, but in the middle of each side or even line up in a row, therefore It would be logical to call just a sticker accordingly, but in order not to depend on external blocks, we put our sticks in container stickers which can be either an independent block or a mix for any block in the item card. Result:



Outwardly, we got the same result, but the markup and styles are different now:

 /* stickers */ .stickers { position: relative; } .sticker { } .sticker_position_0 { position: absolute; left: 0px; top: 0px; } .sticker_position_1 { position: absolute; right: 0px; top: 0px; } .sticker_position_2 { position: absolute; left: 0px; bottom: 0px; } .sticker_position_3 { position: absolute; right: 0px; bottom: 0px; } .sticker__img { border: none; padding: 0; } 

As I said earlier, the .stickers container can be either an independent block or a mix for any block in the item card. In this case, we mixed it to the .image block by dividing their assignments.

Each sticker has a class .sticker , which contains styles common to all sticks, for example, size. But the styles responsible for positioning we bring in the modifier with the key position :



Note:
.sticker can be like an element .stickers :
 <div class="stickers"> <div class="stickers__sticker sticker sticker_position_2"> <img class="sticker__img " src="#"> </div> </div> 
as well as a separate block for dotted layout without context stickers .

Now with a flick of the wrist, you can put stickers anywhere. For example, you can take the sticks out of the image and apply it on the entire product card in the product container:



The main point is that further manipulations will be much simpler, and this code, simply by copying it into another project, will immediately start working, all that remains is to modify it with the necessary properties.

There is still an unresolved problem with these selectors, which previously had an eyesore:

 .box-product .image .corner_3 img {....} .box .box-product .image .corner_2 img {....} 

In general, I never found the box-product to see the context of the problem, so I can’t say with certainty whether such a selector is needed or not, but the BEM methodology does not prohibit nesting if you cannot do without it. With the resulting markup, at a minimum, you can reduce the selector to 2 classes, which will allow you to more precisely interact with elements and, without increasing specificity, you can either redefine or add styles simply by arranging them in the correct order:

 .box-product .sticker__img {...} .box .sticker__img {...} 

Conclusion


This is a very small piece of code in which a lot of meaning is hidden.

It is enough to put one block in order to make it easier to work. You can piece by piece to achieve more stable work even on a completely running project, and even more so you can rewrite one module once and make life easier for everyone.

Thanks to everyone who read to the end and hope that my article was helpful.

Source: https://habr.com/ru/post/457016/


All Articles