Статьи

Архитектура CSS: блочный элемент-модификатор (БЭМ) и атомарный CSS

Ниже приведен небольшой отрывок из новой книги Тиффани « Мастер CSS», 2-е издание .

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

Блок-элемент-модификатор (БЭМ)

BEM , или Block-Element-Modifier, представляет собой методологию, систему именования и набор связанных инструментов. Созданная в Яндексе , БЭМ была разработана для быстрой разработки значительными командами разработчиков. В этом разделе мы сосредоточимся на концепции и системе имен.

Методология BEM побуждает дизайнеров и разработчиков рассматривать веб-сайт как набор повторно используемых блоков компонентов, которые можно смешивать и подбирать для создания интерфейсов. Блок — это просто часть документа, такая как верхний или нижний колонтитул или боковая панель, показанная ниже. Возможно, это сбивает с толку «блок» здесь относится к сегментам HTML, которые составляют страницу или приложение.

Блоки могут содержать другие блоки. Например, блок заголовка может также содержать блоки логотипа, навигации и формы поиска, как показано ниже. Блок нижнего колонтитула может содержать блок карты сайта.

Блок заголовка, который содержит логотип, навигацию и блоки поиска

Более гранулированный элемент, чем блок. Как объясняет документация БЭМ :

Элемент — это часть блока, которая выполняет определенную функцию. Элементы зависят от контекста: они имеют смысл только в контексте блока, к которому они принадлежат.

Например, блок формы поиска содержит элемент ввода текста и элемент кнопки отправки, как показано на рисунке ниже. (Для пояснения мы используем «элемент» в смысле элемента дизайна, а не в смысле элемента HTML.)

Блок поиска с элементами ввода текста и кнопки отправки

С другой стороны, основной блок контента может иметь блок списка статей. Этот блок списка статей может содержать серию рекламных блоков. И каждый промо-блок статьи может содержать элементы изображения, выдержки и «Читать далее», как показано ниже.

Рекламный блок для статьи на сайте

Вместе блоки и элементы составляют основу соглашения об именах БЭМ. По правилам БЭМ:

  • имена блоков должны быть уникальными в рамках проекта
  • имена элементов должны быть уникальными в пределах блока
  • вариации блока — скажем, окно поиска с темным фоном — должны добавить модификатор к имени класса

Имена блоков и имен элементов обычно разделяются двойным подчеркиванием ( .block__element Имена блоков и элементов обычно отделяются от имен модификаторов двойным дефисом (например, .block--modifier.block__element--modifier

Вот как выглядит БЭМ на примере формы поиска:

 <form class="search">
    <div class="search__wrapper">
        <label for="s" class="search__label">Search for: </label>
        <input type="text" id="s" class="search__input">
        <button type="submit" class="search__submit">Search</button>
    </div>
</form>

Вариант этой формы с темным фоном может использовать следующую разметку:

 <form class="search search--inverse">
    <div class="search__wrapper search__wrapper--inverse">
        <label for="s" class="search__label search_label--inverse">Search for: </label>
        <input type="text"  id="s" class="search__input search__input--inverse">
        <button type="submit" class="search__submit search__submit--inverse">Search</button>
    </div>
</form>

Наш CSS может выглядеть так:

 .search {
    color: #333;
}
.search--inverse {
    color: #fff;
    background: #333;
}
.search__submit {
    background: #333;
    border: 0;
    color: #fff;
    height: 2rem;
    display: inline-block;
}
.search__submit--inverse {
    color: #333;
    background: #ccc;
}

И в нашей разметке, и в CSS search--inversesearch__label--inverseдополнительными именами классов. Они не являются заменой для searchsearch__label Имена классов являются единственным типом селектора, используемого в системе БЭМ. Можно использовать селекторы потомка и потомка, но потомки также должны быть именами классов. Селекторы элементов и идентификаторов верботенны. Обеспечение уникальности имен блоков и элементов также предотвращает конфликты имен, которые могут стать проблемой для команд.

У этого подхода есть несколько преимуществ:

  • новым членам команды легко читать разметку и CSS и понимать их поведение
  • добавление большего количества разработчиков повышает производительность команды
  • последовательное именование уменьшает вероятность столкновений имен и побочных эффектов
  • CSS не зависит от разметки
  • CSS очень многоразовый

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

Атомный CSS

Если БЭМ — индустрия, Атомный CSS — его мятежный персонаж. Названный и объясненный Тьерри Кобленцем из Yahoo в его статье 2013 года « Оспаривание лучших практик CSS», в Atomic CSS используется узкая библиотека имен классов. Эти имена классов часто сокращены и отделены от содержимого, на которое они влияют. В системе Atomic CSS вы можете сказать, что делает имя класса, но нет никакой связи между именами классов (по крайней мере, не теми, которые используются в таблице стилей) и типами контента.

Давайте проиллюстрируем на примере. Ниже приведен набор правил, которые мы могли бы назвать традиционной архитектурой CSS. В этих наборах правил используются имена классов, которые описывают содержимое, к которому они применяются — глобальное окно сообщения и стили для окон сообщения «успех», «предупреждение» и «ошибка»:

 .msg {
    background-color: #a6d5fa;
    border: 2px solid #2196f3;
    border-radius: 10px;
    font-family: sans-serif;
    padding: 10px;
}
.msg-success {
    background-color: #aedbaf;
    border: 2px solid #4caf50;
}
.msg-warning {
    background-color: #ffe8a5;
    border-color:  #ffc107;
}
.msg-error {
    background-color: #faaaa4;
    border-color: #f44336;
}

Чтобы создать окно сообщения об ошибке, нам нужно добавить имена классов msgmsg-errorclass

 <p class="msg msg-error">An error occurred.</p>

Давайте сопоставим это с атомарной системой, где каждое объявление становится своим собственным классом:

 .bg-a {
    background-color: #a6d5fa;
}
.bg-b {
    background-color: #aedbaf;
}
.bg-c {
    background-color: #ffe8a5;
}
.bg-d {
    background-color: #faaaa4;
}
.bc-a{
    border-color: #2196f3;
}
.bc-b {
    border-color: #4caf50;
}
.bc-c {
    border-color:  #ffc107;
}
.bc-d {
    border-color:  #f44336;
}
.br-1x {
    border-radius: 10px;
}
.bw-2x {
    border-width: 2px;
}
.bss {
    border-style: solid;
}
.sans {
    font-style: sans-serif;
}
.p-1x {
    padding: 10px;
}

Это намного больше CSS. Давайте теперь воссоздадим наш компонент сообщения об ошибке. Используя атомарный CSS, наша разметка становится:

 <p class="bw-2 bss p-1x sans br-1x bg-d bc-d">
    An error occurred.
</p>

Наша разметка также более многословна. Но что происходит, когда мы создаем компонент с предупреждением?

 <p class="bw-2 bss p-1x sans br-1x bg-c bc-c">
    Warning: The price for that item has changed.
</p>

Два имени класса изменились: bg-dbc-dbg-cbc-c Мы повторно использовали пять наборов правил. Теперь давайте создадим кнопку:

 <button type="button" class="p-1x sans bg-a br-1x">Save</button>

Эй, сейчас! Здесь мы повторно использовали четыре набора правил и не добавляли больше правил в нашу таблицу стилей. В надежной атомарной архитектуре CSS добавление нового компонента HTML, такого как боковая панель статьи, не потребует добавления большего количества CSS (хотя, в действительности, это может потребовать добавления немного больше).

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

  • сохраняет обрезку CSS, создавая очень детализированные, многократно используемые стили вместо набора правил для каждого компонента
  • значительно уменьшает конфликты специфичности, используя систему селекторов с низкой специфичностью
  • позволяет быстро разрабатывать HTML-компоненты после определения начальных наборов правил

Тем не менее, Atomic CSS не без противоречий.

Дело против атомного CSS

Атомный CSS противоречит практически всему, чему нас научили при написании CSS. Это почти так же неправильно, как повсеместно придерживаться атрибутов style Действительно, одна из основных критических замечаний по методологии Atomic CSS заключается в том, что она стирает грань между контентом и представлением. Если class="fl m-1x"

Конечно, один из ответов — удалить класс fl Но теперь мы меняем HTML. Вся причина использования CSS заключается в том, что разметка не зависит от представления и наоборот. (Мы также можем решить эту проблему, удалив правило .fl {float: left;}fl

В оригинальном посте Кобленца он использовал имена классов, такие как .M-10margin: 10px.P-10padding: 10px Проблема с таким соглашением об именах должна быть очевидной. Изменение с полем в пять или 20 пикселей означает, что нам нужно обновить наш CSS и наш HTML или рискнуть иметь имена классов, которые не в состоянии точно описать их эффект.

Использование имен классов, таких как p-1x 1x Если базовый отступ составляет пять пикселей (то есть .p-1x { padding: 5px; }.p-2x Да, это менее наглядно описывает то, что делает имя класса, но это также означает, что мы можем изменить наш CSS без обновления нашего HTML и без создания вводящего в заблуждение имени класса.

Атомная архитектура CSS не мешает нам использовать имена классов, которые описывают содержимое нашей разметки . Вы все еще можете добавить .button-close.accordion-trigger Такие имена классов на самом деле предпочтительнее для манипуляций с JavaScript и DOM.

БЭМ против атомного CSS

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

Атомный CSS работает лучше, когда есть небольшая команда или один инженер, отвечающий за разработку набора правил CSS, с полноценными компонентами HTML, созданными большой командой. С Atomic CSS разработчики могут просто взглянуть на руководство по стилю или исходный код CSS, чтобы определить, какой набор имен классов им понадобится для конкретного модуля.

Знай, когда идти своим путем

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