Pull to refresh

Методология БЭМ на примере стикеров в opencart

Reading time 5 min
Views 4.6K


Поскольку я предпочитаю методологию БЭМ, начав работать с opencart, я сразу же столкнулся с ужасными для меня вещами, это вложенные селекторы. Они повсюду! Начиная от шаблона по умолчанию, заканчивая практически всеми модулями и авторскими шаблонами. Почему так? Мне кажется тут ряд причин:

  1. Opencart по умолчанию построен на вложенных селекторах, как шаблон, так и админка.
  2. Большинство разработчиков, которые работают с opencart являются именно back-end разработчиками, они просто подхватили этот подход
  3. Есть ряд необходимых классов и id к котором привязываются как стандартный функционал opencart, так и авторские модули, и все те же back-end разработчики, а за ними и их последователи, по разным причинам просто не хотят ничего менять и плывут по течению.

Я ни в коем случае не хочу ничего плохого сказать в сторону back-end разработчиков, но многие из них действительно слабы во front-end и даже в верстке. Это мнение сложилось на основе общения с ними, совместной работы и в целом по их активности на тематических форумах opencart. Я подчеркиваю, что имею ввиду именно нишу разработчиков opencart.

Я делаю шаблоны с нуля по методологии БЭМ (насколько это возможно в рамках opencart) и могу с уверенностью сказать, что любой модуль заводится с пол пинка не зависимо от разметки. Модуль о котором ниже пойдет речь вообще не нуждается в каких-либо правках, все что нужно это упростить работу с ним и реализовать возможность его переиспользовать в других проектах. Я взял для примера именно этот модуль, так как он очень прост и не нужно отвлекаться на кучу лишнего кода, но в тоже время он содержит в себе все те проблемы, которые решает БЭМ. Это реально существующий модуль и таких модулей, да и просто шаблонов, очень много. Я считаю, что один боевой пример лучше сотни абстрактных.

Для начала я опишу суть проблемы. В одной из отечественных сборок opencart встроен модуль стикеров. Он выводит выбранный стикер в указанный угол:
Верхний левый / Верхний правый / Нижний левый / Нижний правый
Вариантов стикеров без ограничений, но позиций максимум 4:



Теперь посмотрим на разметку и стили:



Что мы видим:

  1. Все стикеры вложены в блок image
  2. Не смотря на то, что блок image по логике предназначен для хранения изображения товара, все стили стикеров привязаны именно к нему, а теперь посмотрим на весь css и особенно на вложенность в последних строках:

/*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%;
}

Если .image .corner_2 выглядел еще более менее приемлемо, то .box .box-product .image .corner_2 img уже выглядит не так оптимистично… В целом можно догадаться, что где-то у нас появится .box-product без родителя .box и применяться одни стили, а где-то с родителем другие, но тут перед нами всплывает ряд проблем:

  1. Если стикеры вынести за пределы .image, все стили отвалятся, а если мы захватим с собой .image и поместим в другом месте, то применяться стили .image там где они не нужны.
  2. Если вдруг переименуем image, который по логике не является хранилищем для стикеров или .box или .box-product, которые находятся еще выше и уж точно никак не говорят о том что стикеры к ним привязаны, в любом из этих случаев мы не получим ожидаемый результат.
  3. Что если мы захотим .image поместить на один уровень с .box-product? Опять что-то пойдет не так…
  4. Много повторяющихся селекторов в которых меняется только .corner_# и если вдруг мы изменим эту вложенность или захотим перенести код в другой шаблон, то придется менять её везде, а ведь еще могут быть медиа запросы, это просто бесполезная трата времени.
  5. Повышенная специфичность. Данная проблема всегда становится заметна спустя время и часто возлагается на плечи тех, кто не создавал её...

Те кто знаком с методологией БЭМ давно знают об этом, а те кто не знаком я думаю ни раз сталкивались. Давайте попробуем решить эти проблемы.

Поскольку одна из главных задач это возможность переиспользовать код, то мы не можем назвать наши наклейки corner, как раньше, ведь возможно в другом проекте мы захотим, чтобы они были не в уголках, а по середине каждой из сторон или вообще выстроились в ряд, поэтому логично будет назвать соответственно просто sticker, но чтобы не зависеть от внешних блоков, поместим наши стики в контейнер stickers который может быть как независимым блоком, так и миксом для любого блока в карточке товара. Результат:



Внешне мы получили такой же результат, но вот разметка и стили теперь другие:

/* 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;
}

Как я ранее сказал контейнер .stickers может быть как независимым блоком, так и миксом для любого блока в карточке товара. В данном случае мы примиксовали его к блоку .image разделив их назначения.

Каждый стикер имеет класс .sticker, который содержит в себе общие для всех стиков стили, например размер. А вот стили отвечающие за позициониорвание мы выносим в модификатор с ключем position:



Примечание:
.sticker может быть как элементом .stickers:
<div class="stickers">
    <div class="stickers__sticker sticker sticker_position_2">
        <img class="sticker__img " src="#">
    </div>
</div>
так и самостоятельным блоком для точечной расстановки без контекста stickers.

Теперь легким движением руки, можно поставить стикеры в любом месте. Например можно вынести стики за пределы image и применить на всю карточку товара в контейнере product:



Главный смысл в том что дальнейшие манипуляции будут в разы проще, а данный код, просто скопировав его в другой проект сразу же начнет работать, останется только модифицировать его необходимыми свойствами.

Остается еще не решенная проблема с этими селекторами, которые мозолили глаза ранее:

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

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


Вообще я так и не нашел box-product, чтобы увидеть контекст проблемы поэтому не могу с уверенностью сказать, нужен такой селектор или нет, но методология БЭМ не запрещает вложенность, если без неё нельзя обойтись. С полученной разметкой, как минимум можно сократить селектор до 2-х классов, что позволит более точечно взаимодействовать с элементами и не повышая специфичности можно либо переопределить, либо добавить стили просто расставив их в правильной порядке:


.box-product  .sticker__img {...}

.box  .sticker__img {...}


Заключение


Это очень маленький кусочек кода, в котором скрыто много смысла.

Достаточно привести в порядок один блок, чтобы стало проще работать. Можно по кусочкам добиться более стабильной работы даже на полностью запущенном проекте и уж тем более можно переписать один модуль один раз и облегчить жизнь всем.

Спасибо всем, кто дочитал до конца и надеюсь, что моя статья была полезна.
Only registered users can participate in poll. Log in, please.
Вы применяете БЭМ методологию в своих проектах?
27.85% Да (Я front-end разработчик) 22
1.27% Да (Я back-end разработчик) 1
29.11% Да (Я full-stack разработчик) 23
11.39% Нет (Я front-end разработчик) 9
5.06% Нет (Я back-end разработчик) 4
15.19% Нет (Я full-stack разработчик) 12
11.39% Нет, но использую другую методологию 9
12.66% Нет, я не использую никакую методологию 10
79 users voted. 25 users abstained.
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+6
Comments 8
Comments Comments 8

Articles