БЭМ-подход к элементу, чем он может принадлежать и выглядеть по-разному в зависимости от Блока?

Допустим, у меня есть стилизованный флажок (подумайте о дизайне материалов, где немного происходит достижение желаемого стиля флажка). Какой блок отвечает за изменение зависимого от родителя дочернего блока?

Пример компонента — флажок

Итак, у меня есть следующее:

<div class="Checkbox">
    <label class="Checkbox__label">
        <input class="Checkbox__input" type="checkbox" checked=true />
        <span class="Checkbox__icon glyphicon glyphicon-ok"></span>
        <span class="Checkbox__text">{label}</span>
    </label>
</div>

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

Пример других блоков

Флажок с немного другим внешним видом, если говорить в «Компактной панели»:

<div class="Panel Panel--compact">
    <p>Disclaimer.. [text]</p>
    <Checkbox label="I Agree" /> 
</div> 

Вариант 1 — родитель "знает" о ребенке

Итак... должен ли Compact Panel "знать" о различных дочерних блоках и стилизовать их, поэтому:

// Checkbox.scss 
.Checkbox {
    margin: 15px;
    // .. other
}


// Panel.scss
.Panel {
    &.Panel--compact {
        margin: 0;
        padding: 2px;
    }
    &.Panel--compact .Checkbox {
        margin: 0;
        padding: 1px;
    }
}

Вариант второй: ребенок «знает» о родителях

Или панель имеет нулевую осведомленность, и флажок проверяет родительскую область.

// Checkbox.scss 
.Checkbox {
    margin: 15px;
    padding: 15px;
    // .. other
}
.Panel.Panel--compact .Checkbox {
    margin: 0;
    padding: 1px;
}


// Panel.scss
.Panel {
    &.Panel--compact {
        margin: 0;
        padding: 2px;
    }
}

Вариант третий – ?

Может есть другие варианты.


person Chris    schedule 25.04.2016    source источник


Ответы (4)


Обычно с БЭМ, если они выглядят по-разному, они другие.

Обычно.

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

Первый вариант, о котором я упомяну, — это использование селекторов потомков. Вы уже определились с этим выбором и столкнулись с обычной проблемой: «Где этот код?»


В следующих примерах я буду использовать синтаксис LESS, это только для того, чтобы мне было проще продемонстрировать отношения в коде.


Селектор потомков

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

widget.less
.widget {
  &__container {
    ...
  }
  ...
}
checkbox.less
.checkbox {
  &__label {
    ...
  }
  ...

  // using inversion to override checkbox styles in a widget
  // this will render to `.widget .checkbox` instead of
  // `.checkbox .widget` due to the `&` placement
  .widget & {
  }
}

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

Если бы стили были связаны с родительским элементом, изменение порядка родительских стилей относительно дочерних стилей могло бы отрицательно сказаться на отображении стилей.

Рассмотрим этот порядок включения:

site.less
@import 'widget';
@import 'checkbox';

Если бы стили были частью виджета, их можно было бы переопределить селектором такой же специфичности в checkbox.less.

Модификаторы

Я рекомендую использовать модификаторы для состояния. Обычно я не считаю положение или контекст «состоянием», поэтому модификаторы могут быть неуместны. Кроме того, несколько модификаторов для одного и того же элемента может быть трудно обосновать и, следовательно, трудно стилизовать.

Предполагая, что вы не используете модификатор в блоке checkbox, может быть проще добавить модификатор для случая, когда он используется в панели.

.checkbox {
  &__label {
    ...defaults...
  }
  ...defaults...

  &--alt {
    &__label {
      ...overrides...
    }
    ...overrides...
  }
}

Конечно, это требует, чтобы разметка была обновлена ​​для конкретного случая, когда она используется на панели, но тогда вы также открываете возможность использовать флажок с теми же стилями в других местах.

Другой селектор

Я повторю свой первый тезис: Если они выглядят по-разному, они другие.

Это не означает, что вам нужно начинать с нуля с флажка. БЭМ допускает объектно-ориентированные стили. Придумайте новое имя и расширьте* флажок:

checkbox.less
.checkbox {
  &__label {
    ...
  }
  ...
}
checkbox-2.less
@import (reference) 'checkbox';
.checkbox-2 {
  .checkbox;

  &__label {
    ...overrides...
  }
  ...overrides...
}

* в LESS я использую миксин для этого, так как он обычно лучше подходит для расширения и переопределения стилей, чем использование функции :extend языка. Не стесняйтесь использовать функцию :extend, но помните, что порядок селекторов имеет значение.

Рефакторинг необходимости

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

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

  • поля
  • набивка
  • должность
  • сверху, справа, снизу, слева
  • ширина
  • высота
  • сгибаться

Рефакторинг сопряжен с другими проблемами, однако я часто заканчиваю тем, что использую контейнерные элементы div для нормализации области вставки для блоков, содержащих другие блоки; YMMV.


tl;dr: Что выбрать?

Можете ли вы (разумно) обновить разметку?

ДА: если вы можете легко обновить разметку для использования разных классов, я бы рекомендовал расширить блок checkbox как новый блок. Однако называть вещи сложно, поэтому обязательно задокументируйте, где что.

НЕТ: если вы не можете легко обновлять классы, использование модификаторов также не лучший выбор. Я бы рекомендовал пропустить это и вернуться к старому доброму селектору потомков. В БЭМ вы действительно хотите избежать селекторов потомков, но иногда они являются правильным инструментом для работы.

person zzzzBov    schedule 09.05.2016
comment
Чувак, с 5 минутами на часах ты дал ответ. особ. эта строка. Причина, по которой я рекомендую связывать стили с внутренним блоком, заключается в том, что стили будут влиять на флажок, а порядок каскадирования будет важен. -- Это здравая логика, которую я преследовал - Круто - person Chris; 09.05.2016
comment
@ Крис, я бы ответил несколько дней назад, если бы увидел это. Это хороший вопрос, и он затрагивает некоторые продвинутые части БЭМ, которые делают его действительно мощным. - person zzzzBov; 09.05.2016
comment
Таймер делает его более драматичным. Еще раз спасибо, я прочитаю его несколько раз в ближайшие дни, чтобы убедиться, что он усвоился. Я думаю, что такие убедительные ответы проходят через размышления, лежащие в основе решения, а также само решение. - person Chris; 09.05.2016

Согласно этой документации, в БЭМ следует избегать использования вложенных селекторов, но они «подходят для изменения элементов в зависимости от состояния блока или назначенной ему темы». Это означает, что вы можете использовать модификатор блока для стилизации его элементов, но я не смог найти упоминания об использовании модификатора блока для стилизации его дочерних блоков.

Я думаю, что лучшим подходом было бы добавить модификаторы к блокам .Pannel и .Checkbox, например: .Panel--compact и .Checkbox--context-compact. Так вы не создадите между ними зависимости, что является принципом БЭМ.

Если каким-то образом вы не можете добавить модификатор к .Checkbox в зависимости от его контекста, я думаю, что ближайшим вариантом будет второй вариант, когда дочерний элемент ведет себя по-разному в зависимости от состояния его родителя.

person Leonardo Favre    schedule 09.05.2016

Это правильный путь:

Я очень удивлен, почему в принятом ответе не упоминаются смеси БЭМ. В этих сценариях, то есть когда блок должен изменить стиль при использовании в другом блоке, официальная документация BEM рекомендует использовать блок И класс элемента на одном и том же узле DOM.

Итак, в вашем случае это будет разметка:

<div class="Panel Panel--compact">
    <p>Disclaimer.. [text]</p>
    <div class="Checkbox Panel__checkbox" /> <!-- Here is the change -->
</div> 

И это будет CSS/SCSS:

// Checkbox.scss 
.Checkbox {
    margin: 15px;
    padding: 15px;
    // .. other
}


// Panel.scss
.Panel {
    &__checkbox {
        margin: 0;
        padding: 2px;
    }
}

Это действительно так легко и просто. Другие ответы излишне усложняют это, и я не знаю почему, в документации БЭМ есть четкий ответ на этот вопрос. Вы также можете найти множество статей в Интернете, объясняющих ту же технику, которую я только что описал.

person Arad    schedule 10.11.2020

Недавно я начал реактивный проект и хотел бы поделиться своим опытом по стилизации реактивных компонентов.

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

.panel {
  .checkbox {

  }
}

Я использую css-модули. Это супер круто. Этот инструмент может создавать уникальные классы, поэтому вам не нужно беспокоиться о дублировании одного и того же имени в других компонентах. Вы можете узнать больше на их странице git, и в Интернете есть много статей.

Если вы используете sass и вам нужно использовать переменные, вы можете определить отдельный файл sass в другой папке (скажем, ../assets/variables.scss), в файле scss вашего компонента вы можете импортировать его и использовать все переменные. То же самое касается примесей и функций.

В вашем случае не беспокойтесь о дочерних и родительских отношениях, напишите отдельные классы для всех элементов, которые вам нужно стилизовать. Иногда вам может понадобиться настроить таргетинг на детей с помощью parent.

Хорошее чтение

person Ryxle    schedule 09.05.2016
comment
это не методология БЭМ. ОП запросил подход BEM к этому - person nicholaswmin; 09.05.2016
comment
Ваше самое последнее предложение - это то, что я ищу для получения дополнительной информации о том, что иногда вам может понадобиться настроить таргетинг на детей с помощью родителя - подробный ответ, описывающий, как и почему вокруг отношений между родителями и детьми в БЭМ - это в основном то, что мне нужно. - person Chris; 09.05.2016