• Когда использовать микс, а когда модификатор?

    Realetive
    @Realetive
    MODX Ambassador России, самозванный БЭМ-евангелист
    Первое, что нужно научиться делать — находить повторяющиеся сущности (которые в последствии станут Блоками и Элементами). Вы уже пытаетесь сделать это, но пока получается слишком многословно, судя по количеству классов и это, очевидно, сбивает с толку.
    Я уже рассказывал на последнем БЭМапе (https://youtu.be/d4dcGj8abv0) о том, как я ищу эти повторяющиеся закономерности, поэтому постараюсь кратко:
    1) Собираем и группируем «данные»
    Разберём «шапку» и «подвал». И там, и там есть логотип, какая-то навигация, контактная информация, ссылки на соц. сети, в шапке есть кнопка:
    1.1) «Шапка»

    {
      logo: {
        img: 'путь до картинки',
        text: '…',
      },
      contacts: [
        'телефон',
        'email',
        'график работы',
        'адрес',
        'соц. сети',
        'кнопка обратной связи',
      ],
      navigation: [
        'пункт меню…',
        'пункт меню…',
        'пункт меню…',
      ]
    }


    1.2) В «подвале» почти то же самое, что-то в другом порядке, но это неважно, и нет «кнопки обратной связи» из секции «Контактов».

    1.3) Есть ещё самостоятельные секции «Свяжитесь с нами» на главной странице и на странице контактов, которые тоже используют пункты из секции «Контактов» (теперь уже понятно, что такое частое повторение позволяет выделить это в блок).

    1.4) Логотип и навигацию тоже выделим в блоки (я разделил логотип на два элемента — изображение и текст, потому что на малых экранах текст превращается в замыленое нечитаемое говно, поэтому его лучше убрать).

    1.5) Получается какая-то такая структура:

    // Блок логотипа
    {
      logo: [
        { img: '…' },
        { text: '…' },
      ]
    }
    
    // Блок контактов
    {
      contacts: [
        { tel: '…' },
        { email: '…' },
        { schedule: '…' },
        { address: '…' },
        { socials: [
          { vk: '…' },
          { telegram: '…' },
          { instagram: '…' },
        ] },
        { map: '…' },
        { feedback: '…' },
      ]
    }
    
    // Блок навигации
    {
      navigation: [
        { item: '', link: '…' },
        { item: '', link: '…' },
        { item: '', link: '…' },
      ]
    }
    
    // Блок «Шапки»
    {
      header: [
        {
          logo: [] // Тут всё без изменений
        },
        {
          contacts: [
            'tel',
            'email',
            'schedule',
            'address',
            'socials',
            'feedback',
          ]
        },
        {
          navigation: [] // Тут тоже без изменений
        }
      ]
    }
    
    // Блок «Подвала»
    {
      footer: [
        {
          logo: [] // Тут всё без изменений
        },
        {
          navigation: [ // Тут почти без изменений
            // …
            'Марки автомобилей' // Без выпадающего списка
            // …
          ]
        },
        {
          contacts: [
            'tel',
            'email',
            'address',
            'socials',
            'schedule', // Без иконки
          ]
        },
      ]
    }



    2) Вроде, пока хватит. «БЭМизируем» эти данные.
    Структура в формате JSON

    // Блок логотипа
    {
      block: 'logo'
      content: [
        { elem: 'img', src: '…' },
        { text: '…' },
      ]
    }
    
    // Блок контактов
    {
      block: 'contacts'
      content: [
        { elem: 'tel', content: '…' },
        { elem: 'email', content: '…' },
        { elem: 'schedule', content: '…' },
        { elem: 'address', content: '…' },
        { elem: 'socials', content: [
          { elem: 'vk', content: '…' },
          { elem: 'telegram', content: '…' },
          { elem: 'instagram', content: '…' },
        ] },
        { elem: 'map', content: '…' },
        { elem: 'feedback', content: '…' },
      ]
    }
    
    // Блок навигации
    {
      navigation: [
        { item: '', link: '…' },
        { item: '', link: '…' },
        { item: '', link: '…' },
      ]
    }
    
    // Блок «Шапки»
    {
      header: [
        {
          block: 'logo'
        },
        {
          block: 'contacts',
          // У этого блока определённо свой контент,
          // будем отличать его от других вариантов
          // этого блока с помощью модификатора
          mods: { view: 'header' },
          content: [
            { elem: 'tel' },
            { elem: 'email' },
            { elem: 'schedule' },
            { elem: 'address' },
            { elem: 'socials' },
            { elem: 'feedback' },
          ]
        },
        {
          block: 'navigation',
          // Этот блок по внешнему виду отличается от блока в «Подвале»,
          // поэтому обозначим его модификатором
          mods: { view: 'header' },
          content: [
            // …
            // У одного пункта выпадающий список
            {
              elem: 'item',
              item: 'Марки автомобилей',
              elemMods: { dropdown: true },
              content: [
                // …
                { elem: 'subitem', item: 'Infinity', href: '…' }
              ]
            },
            // …
          ]
        }
      ]
    }
    
    // Блок «Подвала»
    {
      footer: [
        {
          block: 'logo'
        },
        {
          block: 'navigation',
          mods: { view: 'footer' },
          content: [ // Тут почти без изменений
            // …
            { elem: 'Марки автомобилей', link: '…' }, // Без выпадающего списка
            // …
          ]
        },
        {
          contacts: [
            'tel',
            'email',
            'address',
            'socials',
            { elem: 'schedule', elemMods: { noIcon: true } }, // Без иконки
          ]
        },
      ]
    }


    2.1) Базовый лэйаут: https://codepen.io/Realetive/pen/PoGRjZo
    2.2) Добавляем обёртки для группировки некоторых элементов: https://codepen.io/Realetive/pen/KKgoBdN
    Про обёртки и зачем они нужны уже обсуждалось в https://ru.bem.info/forum/656/, очень советую.
    2.3) Добавим отступы: https://codepen.io/Realetive/pen/bGwvjow
    Как видите, миксы по-прежнему не нужны.
    3) У контента есть фиксированная ширина, обозначим её через класс-элемент блока page: например, .page__layout:
    https://codepen.io/Realetive/pen/WNGzgjJ
    Но вёрстка закономерно сбилась, потому что классы, которые мы назначали для родительского уровня, «поднялись» ещё н один уровень. Добавим ещё обёртки, чтобы «выровнять» лэйаут: стили header перенесутся в header__body, из footer в footer__body: https://codepen.io/Realetive/pen/wvzmEpy
    4) Получилось достаточно много «лишних» обёрток только лишь для позиционирования. Можно было бы этого избежать, если бы стили были описаны в одном классе. Но тогда мы лишимся пользы разделения логики благодаря БЭМ-неймингу. Вместо этого объединим эти слои с помощью миксов: page__header + header, header__body + page__layout, page__footer + footer, footer__body + page__layout: https://codepen.io/Realetive/pen/RwGMYyV

    Вот наконец и пригодились миксы. Они лишь позволяют объединить две сущности по схожему признаку (например, лэйаут и позиционирование) на одном теге. А модификаторы обозначают различие между двумя одинаковыми сущностями (например, в одном месте у элемента есть иконка, в другом — нет, хотя это всё тот же элемент).

    Блок с контактами делается аналогичным способом:
    .page__section.page__section_view_feedback
      .page__layout
        .form.form_view_feedback.page__column_width_half (миксуем блок формы обратной связи и лэйаут 1/2 колонки)
          …
        .contacts_view_feedback.page__column_width_half
          .contacts__info
            .contacts__address
            .contacts__email
            .contacts__tel
            .contacts__schedule
          .contacts__map
    Ответ написан
    1 комментарий