BEM methodology on the example of stickers in opencart
- Tutorial
Since I prefer the BEM methodology, when I started working with opencart, I immediately ran into terrible things for me, these are nested selectors. They are everywhere! Starting from the default template, ending with almost all modules and copyright templates. Why is that? I think there are a number of reasons:
- Opencart is built by default on nested selectors, both a template and an admin panel.
- Most developers who work with opencart are back-end developers, they just picked up this approach
- There are a number of necessary classes and an id to which both the standard opencart functionality and the author’s modules are bound, 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.
By no means do I want to say anything bad towards the back-end developers, but many of them are really weak in the front-end and even in layout. This opinion was formed on the basis of communication with them, collaboration and, in general, their activity on thematic opencart forums. I emphasize that I mean the niche of opencart developers.
I make templates from scratch according to the BEM methodology (as much as possible within the framework of opencart) and I can say with confidence that any module starts with a half kick regardless of the markup. The module which will be discussed below does not need any corrections at all, all that is needed is to simplify the work with it and realize the possibility of reusing it in other projects. I took this module as an example, since 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 existing module and there are a lot of such modules, and there are just templates. I believe that one combat example is better than hundreds of abstract ones.
First, I will describe the essence of the problem.. In one of the domestic opencart assemblies, a sticker module is integrated. It displays the selected sticker in the specified corner:
Upper left / Upper right / Lower left / Lower right
There are no options for stickers, but there are a maximum of 4 positions:
Now let's look at the layout and styles:
What we see:
- All stickers are embedded in the image block.
- Despite the fact that the image block is logically designed to store the image of the product, all styles of stickers are tied to it, and now look at the whole css and especially on 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 does not look so optimistic ... In general, we can guess that somewhere we will have .box-product without a parent .box and some styles are used, but somewhere with the parent others, but here we face a number of problems:
- If the stickers are moved outside the .image , all styles will fall off, and if we take .image with us and place them in another place, then apply .image styles where they are not needed.
- 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 say that the stickers are attached to them, in any of these cases we will not get the expected result .
- What if we want to put .image on par with .box-product ? Again, something will go wrong ...
- There are many repeating 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.
- 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 I have come across more than once. Let's try to solve these problems.
Since one of the main tasks is the ability to reuse the code, we cannot name our stickers corner, as before, because perhaps in another project we want them not to be in the corners, but in the middle of each of the sides or in general lined up, therefore it would be logical to call it simply sticker, respectively, but in order not to depend on external blocks, put our sticks in the stickers container, which can be either an independent block or a mix for any block in the product’s card. Result:
Externally, we got the same result, but the markup and styles are now different:
/* 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 product 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 we take out styles responsible for positioning in the modifier with the position key :
Note:
.sticker can be as an element .stickers :
as well as an independent block for dot placement 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 to the entire product card in the product container:
The main point is that further manipulations will be much easier, and this code, just copying it to another project, will immediately start working, it remains only to modify it with the necessary properties .
There is still an unresolved problem with these selectors, which callused eyes earlier:
.box-product .image .corner_3 img {....}
.box .box-product .image .corner_2 img {....}
In general, I never found 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 least you can reduce the selector to 2 classes, which will allow more precise interaction 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 that makes a lot of sense.
It is enough to tidy up one block to make it easier to work. It is possible to achieve more stable work in pieces even on a fully launched 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 I hope that my article was useful.
Only registered users can participate in the survey. Please come in.
Do you apply BEM methodology in your projects?
- 27.3% Yes (I'm a front-end developer) 20
- 1.3% Yes (I'm a back-end developer) 1
- 28.7% Yes (I'm a full-stack developer) 21
- 10.9% No (I'm a front-end developer) 8
- 5.4% No (I'm a back-end developer) 4
- 16.4% No (I'm a full-stack developer) 12
- 12.3% No, but using a different methodology 9
- 12.3% No, I do not use any methodology 9