- Понятие уровня переопределения
- Задачи уровней переопределения
- Порядок использования уровней переопределения
- Примеры
Уровень переопределения — это директория в БЭМ-проекте, которая содержит файлы реализаций блоков, элементов и модификаторов.
Любой БЭМ-проект состоит из уровней переопределения. Минимальное количество уровней в проекте — один, максимальное – не ограничено.
Пример файловой структуры БЭМ-проекта с одним уровнем переопределения:
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
на уровне проекта 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); /* Параметры тени */
}
Новый вид кнопки:
В результате:
- Исходная реализация блока
button
не изменяется. - Проектные изменения для блока
button
применятся ко всем кнопкам проекта. - При обновлении библиотеки до новой версии, изменения блоков, которые сделаны для проекта, сохранятся на другом уровне переопределения. Если в новой версии библиотеки изменится фон кнопки или ее размеры, в проекте для блока
button
все равно применятся переопределенные правила.
В одном проекте можно настраивать разные варианты сборки: определять последовательность и множество уровней для каждого отдельного случая. Например, для каждой страницы проекта можно настроить свое используемое множество уровней.
Пример показывает разделение проекта на платформы по уровням переопределения.
На схеме показана сборка проекта для разных платформ в зависимости от юзер-агента:
Наиболее распространенные способы использования уровней переопределения:
- Разделение проекта на платформы
- Обновление библиотеки блоков в проекте
- Разработка проектов, в которых используются общие блоки
- Создание разных тем оформления проекта
- Эксперименты в рабочем проекте
В проекте, поддерживающем разные платформы (например, mobile
и desktop
), часть кода описывает общую функциональность и часть — специфичную для каждой платформы. Чтобы не копировать общий код для реализации каждой из платформ, используются уровни переопределения.
Общие реализации блоков для всех платформ находятся на одном уровне, например, common.blocks
, а специфические реализации блоков для мобильных и настольных устройств на двух других:
common.blocks
— общие реализации блоков для всех платформ;desktop.blocks
— специфические реализации блоков для настольных устройств;mobile.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-код.
Чтобы убрать из проекта неподходящий вариант, достаточно удалить директорию — уровень переопределения неудачного эксперимента.
Пример ниже показывает добавление нескольких экспериментов в файловую структуру рабочего проекта:
- изменение аватарки пользователя (блок
user-pic
); - изменение отступов в шапке (блок
header
); - изменение шрифта для имени пользователя (блок
user-name
).
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/ # новый вид аватарки пользователя
Чтобы увидеть изменения, достаточно подключить уровень эксперимента в сборку.