Статьи

Использование PostCSS с методиками BEM и SUIT

В этом уроке мы узнаем, как использовать PostCSS, чтобы сделать разработку CSS в стиле BEM / SUIT более простой и эффективной.

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

БЭМ был предшественником этой методологии именования классов, созданной Яндексом. Методология SUIT — это подход, основанный на БЭМ, но с некоторыми изменениями и дополнениями, внесенными Николасом Галлахером. SUIT делает все, что делает BEM, но для многих пользователей это считается улучшением.

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

Плагин postcss-bem от Malte-Maurice Dreyer устраняет эти проблемы с помощью сочетания клавиш и вложения, которые вы научитесь использовать при прохождении этого урока.

Но сначала давайте кратко ознакомимся с методами BEM и SUIT, чтобы убедиться, что у вас есть четкое представление о преимуществах использования плагина postcss-bem и о том, как он используется.

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

Например, поисковая форма «блоки» на вашем сайте может использовать класс .search-form .

Элемент в БЭМ является подразделом внутри блока. Они обозначаются добавлением разделителя __ с двумя подчеркиваниями и имени элемента к имени родительского блока.

Например, форма поиска может включать заголовок, текстовое поле и элементы кнопки «Отправить». Их имена классов могут быть .search-form__heading , .search-form__text-field и .search-form__submit-button соответственно.

Модификатор применяется к блоку или элементу для обозначения изменения его представления или изменения его состояния. Они обозначаются добавлением разделителя и имени модификатора к рассматриваемому блоку или элементу.

Официальные документы сайта БЭМ гласят, что разделители модификаторов должны быть одним подчеркиванием _ . Тем не менее, в «БЭМ-подобном» соглашении CSS Guidelines Гарри Робертса используются две черты -- и, вероятно, оно более широко используется и известно, чем официальное соглашение БЭМ.

Например, в дизайне может потребоваться представить формы расширенного поиска иначе, чем обычные формы поиска, и, следовательно, создать класс модификатора .search-form_advanced (официальный BEM) или .search-form--advanced (BEM-like).

В другом примере вам может потребоваться изменить внешний вид формы из-за изменения состояния, например, если недопустимое содержимое было только что отправлено, и, следовательно, создать модификатор .search-form_invalid (официальный BEM) или .search-form--invalid (БЭМ-подобный).

SUIT включает в себя коммунальные услуги и компоненты . Внутри компонентов могут быть Модификаторы , Потомки и Состояния .

В SUIT используется комбинация паскаля (PascalCase), верблюда (camelCase) и тире. Его соглашения устанавливают ограничение на иногда запутанное количество черточек и подчеркиваний, которые могут появляться в БЭМ. Например, класс BEM .search-form__text-field будет иметь вид .SearchForm-textField в SUIT.

Утилиты обрабатывают структуру и позиционное моделирование и написаны таким образом, что их можно применять в любом месте компонента. Они имеют префикс u- и написаны в случае верблюда. Например, .u-clearFix .

Компонент в SUIT занимает место блока в BEM. Компоненты всегда пишутся в паскале и являются только частью SUIT, в которой используется паскаль, что делает их легко идентифицируемыми. Например, .SearchForm .

Компоненты могут опционально иметь префикс с пространством имен и одной чертой nmsp- чтобы гарантировать предотвращение конфликтов, например .mine-SearchForm .

Потомок в SUIT заменяет элемент в BEM. Он использует одну черту - и написано в случае верблюда. Например .SearchForm-heading , .SearchForm-textField и .SearchForm-submitButto .

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

Модификаторы написаны в случае верблюда и начинаются с двух черточек -- . Например, .SearchForm--advanced .

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

Состояния имеют префикс is- и пишутся в случае верблюда. Они также всегда пишутся как смежные классы. Например .SearchForm.is-invalid .

Теперь, когда у вас есть основы BEM и SUIT, пришло время настроить ваш проект.

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

О том, как настроить проекты Gulp или Grunt для PostCSS, вы можете прочитать в предыдущих уроках

соответственно.

Если вы не хотите вручную настраивать свой проект с нуля, вы можете загрузить исходные файлы, прикрепленные к этому учебному пособию , и извлечь предоставленный стартовый проект Gulp или Grunt в пустую папку проекта. Затем с помощью терминала или командной строки, указывающей на папку, выполните команду npm install .

Далее вам нужно установить плагин postcss-bem. Мы также установим плагин, который может работать с ним довольно хорошо: postcss-nested .

Используете ли вы Gulp или Grunt, выполните следующую команду в папке вашего проекта:

1
npm install postcss-bem postcss-nested —save-dev

Теперь мы готовы загрузить плагины в ваш проект.

Если вы используете Gulp, добавьте эти переменные под переменными, уже имеющимися в файле:

1
2
var bem = require(‘postcss-bem’);
var nested = require(‘postcss-nested’);

Теперь добавьте каждое из этих новых имен переменных в ваш массив processors :

1
2
3
4
var processors = [
       bem,
       nested
   ];

Проведите быструю проверку того, что все работает, запустив команду gulp css проверив, что новый файл «style.css» появился в папке dest вашего проекта.

Если вы используете Grunt, обновите объект processors , который вложен в объект options , следующим образом:

1
2
3
4
processors: [
         require(‘postcss-bem’)(),
         require(‘postcss-nested’)()
       ]

grunt postcss быструю проверку того, что все работает, запустив команду grunt postcss проверив, что новый файл style.css появился в папке dest вашего проекта.

Хорошо, ты готов к работе. Давайте узнаем, как генерировать структуру BEM и SUIT.

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

Однако, когда вы используете postcss-bem, становится легко разобраться в структуре вашего кода, и повторение при наборе имен классов становится практически несуществующим.

Несмотря на свое имя, по умолчанию postcss-bem будет выводиться в соответствии с синтаксисом SUIT, а не BEM. Вы можете выводить в синтаксисе БЭМ, который мы рассмотрим позже, но плагин в первую очередь предназначен для вывода SUIT, поэтому по этой причине мы начнем с синтаксиса SUIT.

Чтобы создать компонент, используйте синтаксис @component ComponentName {...} .

Попробуйте это, добавив компонент SearchForm в файл «src / style.css»:

1
2
3
4
@component SearchForm {
    padding: 0;
    margin: 0;
}

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

1
2
3
4
.SearchForm {
  padding: 0;
  margin: 0;
}

Чтобы создать потомок, используйте синтаксис @descendent descName {...} вложенный в родительский компонент.

Добавьте потомок с именем textField внутри вашего компонента SearchForm следующим образом:

01
02
03
04
05
06
07
08
09
10
@component SearchForm {
    padding: 0;
    margin: 0;
     
    /* Nest descendent under component */
    @descendent textField {
        border: 1px solid #ccc;
    }
 
}

После компиляции вы должны увидеть:

1
2
3
4
5
6
7
8
.SearchForm {
    padding: 0;
    margin: 0;
}
 
.SearchForm-textField {
    border: 1px solid #ccc;
}

Создайте модификатор для компонента с синтаксисом @modifier name {...} , вложенным в компонент, на который он воздействует. Модификаторы обычно следует размещать в верхней части вашего компонента, выше любых потомков и состояний.

Добавьте модификатор с именем advanced в свой компонент SearchForm со следующим кодом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@component SearchForm {
    padding: 0;
    margin: 0;
     
    /* Typically, place modifiers above descendents */
    @modifier advanced {
        padding: 1rem;
    }
     
    @descendent textField {
        border: 1px solid #ccc;
    }
 
}

Перекомпилируйте ваш код, и вы должны увидеть свой новый advanced модификатор компонента:

01
02
03
04
05
06
07
08
09
10
11
12
.SearchForm {
    padding: 0;
    margin: 0;
}
 
.SearchForm—advanced {
    padding: 1rem;
}
 
.SearchForm-textField {
    border: 1px solid #ccc;
}

Состояния создаются с помощью синтаксиса @when name {...} и могут быть вложены в компонент или потомок.

Добавьте состояние с именем invalid для вашего textField используя этот код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
@component SearchForm {
    padding: 0;
    margin: 0;
     
    @modifier advanced {
        padding: 1rem;
    }
     
    @descendent textField {
        border: 1px solid #ccc;
         
        /* This creates a state for the textField descendant */
        @when invalid {
            border: 1px solid red;
        }
    }
 
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
.SearchForm {
    padding: 0;
    margin: 0;
}
 
.SearchForm—advanced {
    padding: 1rem;
}
 
.SearchForm-textField {
    border: 1px solid #ccc;
}
 
.SearchForm-textField.is-invalid {
    border: 1px solid red;
}

Вы можете именовать свои компоненты и все потомки, модификаторы и состояния, вложенные в них, окружая их @component-namespace name {...} . Вы можете, если хотите, обернуть всю таблицу стилей этим пространством имен, чтобы все ваши классы автоматически имели префикс.

Попробуйте это, обернув весь свой код до сих пор с помощью @component-namespace mine {...} :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
@component-namespace mine {
 
    @component SearchForm {
        padding: 0;
        margin: 0;
         
        @modifier advanced {
            padding: 1rem;
        }
         
        @descendent textField {
            border: 1px solid #ccc;
             
            @when invalid {
                border: 1px solid red;
            }
        }
 
    }
 
}

После компиляции вы увидите, что теперь каждый из ваших компонентов имеет префикс mine- :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
.mine-SearchForm {
    padding: 0;
    margin: 0;
}
 
.mine-SearchForm—advanced {
    padding: 1rem;
}
 
.mine-SearchForm-textField {
    border: 1px solid #ccc;
}
 
.mine-SearchForm-textField.is-invalid {
    border: 1px solid red;
}

Утилиты создаются с использованием синтаксиса @utility utilityName {...} . Вы помните, что при настройке своего проекта вы установили плагин, вложенный в postcss. Мы сделали это, так как это может быть очень удобно использовать в унисон с postcss-bem, как вы увидите в этом примере, где мы создаем утилиту clearFix :

01
02
03
04
05
06
07
08
09
10
11
@utility clearFix {
    &:before, &:after {
        content: «»;
        display: table;
    }
    &:after {
        clear: both;
    }
    /* If supporting IE 6/7 */
    *zoom: 1;
}

После добавления приведенного выше кода, скомпилируйте, и вы увидите, что эта новая утилита была создана:

01
02
03
04
05
06
07
08
09
10
11
12
13
.u-clearFix {
    /* If supporting IE 6/7 */
    zoom: 1;
}
 
.u-clearFix:before, .u-clearFix:after {
    content: «»;
    display: table;
}
 
.u-clearFix:after {
    clear: both;
}

Чтобы активировать вывод синтаксиса BEM в postcss-bem, передайте style: 'bem' опции style: 'bem' в вашем Gulpfile или Gruntfile следующим образом:

01
02
03
04
05
06
07
08
09
10
11
/* Gulpfile */
var processors = [
    bem({style: ‘bem’}),
    nested
];
     
/* Gruntfile */
processors: [
    require(‘postcss-bem’)({style: ‘bem’}),
    require(‘postcss-nested’)()
]

По умолчанию postcss-bem будет использовать официальный разделитель для модификатора одиночного подчеркивания _ . Если для вашего проекта важно использовать более общий разделитель двух тире -- вместо этого вы можете изменить конфигурацию для плагина postcss-bem, перейдя в папку node_modules / postcss-bem вашего проекта, открыв index.js , найти строку 15 и изменить это:

1
2
3
4
5
6
7
bem: {
       separators: {
           namespace: ‘—‘,
           descendent: ‘__’,
           modifier: ‘_’
       }
   }

…к этому:

1
2
3
4
5
6
7
bem: {
       separators: {
           namespace: ‘_’,
           descendent: ‘__’,
           modifier: ‘—‘
       }
   }

Поскольку «блок» в БЭМ коррелирует с «компонентом» в SUIT, используйте синтаксис @component block-name {...} для генерации блока.

Чтобы создать блок search-form добавьте этот код:

1
2
3
4
@component search-form {
    padding: 0;
    margin: 0;
}

Затем скомпилируйте и вы увидите:

1
2
3
4
.search-form {
    padding: 0;
    margin: 0;
}

Поскольку «элемент» в БЭМ соотносится с «потомком» в SUIT, они могут быть созданы с помощью синтаксиса @descendent element-name {...} вложенного в родительский блок.

Чтобы создать элемент text-field добавьте следующее:

1
2
3
4
5
6
7
8
9
@component search-form {
    padding: 0;
    margin: 0;
     
    @descendent text-field {
        border: 1px solid #ccc;
    }
 
}

При компиляции вы увидите, что ваш новый элемент создан:

1
2
3
4
5
6
7
8
.search-form {
    padding: 0;
    margin: 0;
}
 
.search-form__text-field {
    border: 1px solid #ccc;
}

Несмотря на то, что BEM допускает модификаторы как для блоков, так и для элементов, плагин postcss-bem будет обрабатывать их, только если они вложены в блоки, а не в элементы, из-за соглашения SUIT о модификаторах, применяемых к компонентам, а не к потомкам. Они могут быть созданы с синтаксисом @modifier name {...} , вложенным в его родительский блок.

Добавьте advanced модификатор к вашему компоненту search-form например так:

01
02
03
04
05
06
07
08
09
10
11
12
13
@component search-form {
    padding: 0;
    margin: 0;
         
    @modifier advanced {
        padding: 1rem;
    }
     
    @descendent text-field {
        border: 1px solid #ccc;
    }
 
}

И при компиляции это даст:

01
02
03
04
05
06
07
08
09
10
11
12
.search-form {
    padding: 0;
    margin: 0;
}
 
.search-form_advanced {
    padding: 1rem;
}
 
.search-form__text-field {
    border: 1px solid #ccc;
}

В то время как в режиме @utility синтаксис @utility и @when не будет компилироваться во что-либо, учитывая, что BEM не использует утилиты или состояния.

Однако, хотя он не является частью BEM, синтаксис @component-namespace все равно будет работать, если вы захотите использовать его в своей таблице стилей BEM. Это будет префикс ваших классов с name-- :

01
02
03
04
05
06
07
08
09
10
11
12
.mine—search-form {
    padding: 0;
    margin: 0;
}
 
.mine—search-form_advanced {
    padding: 1rem;
}
 
.mine—search-form__text-field {
    border: 1px solid #ccc;
}

Теперь вы знаете все о том, как ускорить разработку BEM и SUIT и упростить весь процесс. Давайте обобщим все, что мы рассмотрели:

  • BEM и SUIT — это соглашения об именах классов, которые помогают ориентировать и организовывать функции таблиц стилей, а также помогают другим разработчикам распознавать назначение различных классов.
  • SUIT похож на BEM, но с некоторыми дополнениями и изменениями
  • Плагин postcss-bem предоставляет ярлыки для создания классов BEM и SUIT, таких как @component , @descendent , @modifier и т. Д.
  • Плагин также позволяет вкладывать код полезным способом, например, модификаторы вкладываются в компонент или блок, который они модифицируют.
  • Пространство имен можно сделать автоматически, обернув классы @component-namespace name {...}

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

Увидимся там!