EN RU
Форум

Методология

Технологии

Инструментарий

Библиотеки

Учебные материалы

Уровни переопределения

Понятие уровня переопределения

Уровень переопределения — это директория в БЭМ-проекте, которая содержит файлы реализаций блоков, элементов и модификаторов.

Любой БЭМ-проект состоит из уровней переопределения. Минимальное количество уровней в проекте — один, максимальное – не ограничено.

Пример файловой структуры БЭМ-проекта с одним уровнем переопределения:

project/
    common.blocks/  # уровень переопределения с блоками проекта
        header/
        footer/

Уровни переопределения позволяют:

Задачи уровней переопределения

Уровни переопределения решают следующие задачи:

Добавление блоков в проект

Блоки с любого уровня могут использоваться в проекте без изменений.

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

Файловая структура проекта с подключенным уровнем библиотеки:

project/
    common.blocks/    # уровень переопределения с блоками проекта
        header/
        logo/
    library.blocks/   # уровень переопределения c блоками библиотеки
        button/       # блок button 

В результате сборки проекта блок button будет подключен в проект:

@import "common.blocks/header/header.css";  /* header с уровня общих блоков проекта */
@import "common.blocks/logo/logo.css";      /* logo с уровня общих блоков проекта */
@import "library.blocks/button/button.css"; /* button с уровня библиотеки */

Подробнее о сборке БЭМ-проектов и порядке подключения БЭМ-сущностей в проект.

Изменение реализации блока

Блоки с любого уровня можно изменять под требования проекта на другом уровне переопределения:

Важно В БЭМ-проекте любую технологию реализации блока можно переопределить или доопределить. Подробнее читайте в разделе Платформа.

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

Важно При переопределении или доопределении исходная реализация блока не изменяется.

Схема показывает подключение БЭМ-сущностей с разных уровней переопределения в сборку:

схема работы уровней переопределения

Пример ниже показывает, как изменить реализации блока button из сторонней библиотеки, которая подключена в проект как отдельный уровень (library.blocks):

project/
    common.blocks/    # уровень переопределения с блоками проекта
        header/
        logo/
    library.blocks/   # уровень переопределения c блоками библиотеки
        button/       # блок button 

Исходная CSS-реализация блока button:

CSS-реализация:

/* Блок button в технологии CSS на уровне library.blocks */

.button {
    position: absolute;
    border: 1px solid rgba(0,0,0,.2);
    border-radius: 3px;
    background-color: #fff;
}

Отображение:

button-default

Чтобы внести изменения, необходимо:

Для этого необходимо создать блок button на уровне проекта common.blocks и разместить в нем файл button.css с новыми стилями для кнопки.

Файловая структура проекта с блоком button на уровне common.blocks:

project/
    common.blocks/       # уровень переопределения с блоками проекта
        header/
        logo/
        button/
            button.css   # новые правила для блока button
    library.blocks/      # уровень переопределения c блоками библиотеки
        button/          # блок button 
            button.css
            button.js

Новые CSS-правила:

/* Блок button в технологии CSS на уровне common.blocks */

.button {
    background-color: #ffdf3a;            /* Новый цвет кнопки */
    width: 150px;                         /* Ширина кнопки */
    box-shadow: 0 0 10px rgba(0,0,0,0.5); /* Параметры тени */
}

В результате сборки реализация блока button будет состоять из исходных CSS-правил с уровня library.blocks и добавленных — с уровня common.blocks:

@import "library.blocks/button/button.css";  /* Исходные CSS-правила с уровня библиотеки */
@import "common.blocks/button/button.css";   /* Особенности с уровня common.blocks*/

Повторяющееся свойство (background-color) будет переопределено (фон кнопки изменится на желтый), а новые свойства (width и box-shadow) — добавлены. Блоку button применится следующий набор свойств:

.button {
    position: absolute;
    border: 1px solid rgba(0,0,0,.2);
    border-radius: 3px;
    background-color: #ffdf3a;             /* Новый цвет кнопки */
    width: 150px;                          /* Ширина кнопки */
    box-shadow: 0 0 10px rgba(0,0,0,0.5);  /* Параметры тени */
}

Новый вид кнопки:

Переопределенная кнопка

В результате:

Порядок использования уровней переопределения

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

Пример показывает разделение проекта на платформы по уровням переопределения.

На схеме показана сборка проекта для разных платформ в зависимости от юзер-агента:

Уровни переопределения

Примеры использования уровней переопределения

Наиболее распространенные способы использования уровней переопределения:

Разделение проекта на платформы

В проекте, поддерживающем разные платформы (например, mobile и desktop), часть кода описывает общую функциональность и часть — специфичную для каждой платформы. Чтобы не копировать общий код для реализации каждой из платформ, используются уровни переопределения.

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

Пример файловой структуры проекта с разными платформами:

project/
    common.blocks/
        button/
            button.css   # базовая CSS-реализация кнопки

    desktop.blocks/   
        button/
            button.css   # особенности кнопки для настольных устройств

    mobile.blocks/
        button/
            button.css   # особенности кнопки для мобильных устройств

При сборке в файл desktop.bundles/bundle/bundle.css попадут все базовые CSS-правила кнопки с уровня common.blocks и переопределенные правила с уровня desktop.blocks.

@import "common.blocks/button/button.css";   /* Базовые CSS-правила */
@import "desktop.blocks/button/button.css";  /* Особенности для настольных устройств */

Файл mobile.bundles/bundle/bundle.css будет включать базовые CSS-правила кнопки с уровня common.blocks и переопределенные правила с уровня mobile.blocks.

@import "common.blocks/button/button.css";   /* Базовые CSS-правила */
@import "mobile.blocks/button/button.css";   /* Особенности для мобильных устройств */

Разделение кода по отдельным уровням переопределения позволяет иметь одновременно разные сборки одного проекта и предоставлять необходимый вариант в зависимости от юзер-агента.

Обновление подключенных библиотек блоков

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

В примере библиотека подключена в проект как уровень переопределения library.blocks:

project/
    common.blocks/     # уровень переопределения с блоками проекта
        header/
        logo/
    library.blocks/    # уровень переопределения c блоками библиотеки
        button/                          

Чтобы использовать кнопку из библиотеки (блок button) в проекте, необходимо изменить высоту кнопки с 18px на 24px. Для этого нужно переопределить блок button на уровне проекта:

project/
    common.blocks/       # уровень переопределения с блоками проекта
        button/
            button.css   # переопределенные правила кнопки
        header/
        logo/
    library.blocks/      # уровень переопределения c блоками библиотеки
        button/          # реализация кнопки в библиотеке

При обновлении библиотеки, переопределенное правило блока button (высота 24px) сохранится, так как переопределение не затрагивает исходную реализацию блока и находится на другом уровне переопределения.

Разработка проектов, в которых используются общие блоки

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

Ниже показан пример файловой структуры проекта, где общие для двух проектов блоки вынесены на отдельный уровень common.blocks:

projects/
    common.blocks/       # общие блоки для нескольких проектов
        button/
        input/

    project-1/           # проект 1
        button/          # переопределение блока button для проекта 1
        logo/
        modal/          

    project-2/           # проект 2
        button/          # переопределение блока b1 для проекта 2
        search/
        spin/         

Создание разных тем оформления проекта

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

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

project/
    common.blocks/       # общие блоки для описания бизнес-логики проекта
        button/
        input/
        ...
    alfa/                # тема оформления alfa
        button/
        input/
    beta/                # тема оформления beta
        button/
        input/

Эксперименты в рабочем проекте

Уровни переопределения позволяют проводить A/B-тестирование непосредственно в рабочем проекте. Во время экспериментов код рабочего проекта не изменяется, так как каждый эксперимент находится на отдельном уровне переопределения.

Можно проводить эксперименты, меняя стили блока, его поведение или разметку страницы. Например, чтобы обеспечить доступность сайта (a11y), необходимо провести эксперименты по добавлению новых тегов на страницу. Для этого на уровне эксперимента необходимо переопределить шаблоны и JavaScript-код.

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

Пример ниже показывает добавление нескольких экспериментов в файловую структуру рабочего проекта:

project/                    
    common.blocks/      # блоки проекта
        header/               
        user-name/          
        user-pic/           
        ...
    exps/
        exp-1/          # уровень для эксперимента №1 
            header/     # новые отступы в шапке          
            user-name/  # новый шрифт для имени пользователя    
            user-pic/   # новый вид аватарки пользователя       
        exp-2/          # уровень для эксперимента №2
            header/     # новые отступы в шапке          
            user-name/  # новый шрифт для имени пользователя    
            user-pic/   # новый вид аватарки пользователя       
        exp-n/          # уровень для любого нового эксперимента
            header/     # новые отступы в шапке          
            user-name/  # новый шрифт для имени пользователя    
            user-pic/   # новый вид аватарки пользователя       

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