[css] BEM
国内许多翻译的资料与官方文档对比有许多出入之处,多以概念理解为主
Block
A functionally independent page component that can be reused.
In HTML, blocks are represented by the class attribute.
Features:
The block name describes its purpose ("What is it?" — menu or button),
not its state ("What does it look like?" — red or big).
<!-- Correct. The `error` block is semantically meaningful -->
<div class="error"></div>
<!-- Incorrect. It describes the appearance -->
<div class="red-text"></div>
The block shouldn't influence its environment,
meaning you shouldn't set the external geometry (margin) or positioning for the block.
You also shouldn't use CSS tag or ID selectors when using BEM.
Block Nesting
Blocks can be nested in each other.
You can have any number of nesting levels.
<!-- `header` block -->
<header class="header">
<!-- Nested `logo` block -->
<div class="logo"></div>
<!-- Nested `search-form` block -->
<form class="search-form"></form>
</header>
Element
A composite part of a block that can't be used separately from it.
Features:
The element name describes its purpose ("What is this?" — item, text, etc.),
not its state ("What type, or what does it look like?" — red, big, etc.).
The structure of an element's full name is block-name__element-name.
The element name is separated from the block name with a double underscore __
.
<!-- `search-form` block -->
<form class="search-form">
<!-- `input` element in the `search-form` block -->
<input class="search-form__input">
<!-- `button` element in the `search-form` block -->
<button class="search-form__button">Search</button>
</form>
Element Nesting
Elements can be nested inside each other.
You can have any number of nesting levels.
An element is always part of a block, not another element.
This means that element names can't define a hierarchy such as block__elem1__elem2
.
<!--
Correct. The structure of the full element name follows the pattern:
`block-name__element-name`
-->
<form class="search-form">
<div class="search-form__content">
<input class="search-form__input">
<button class="search-form__button">Search</button>
</div>
</form>
<!--
Incorrect. The structure of the full element name doesn't follow the pattern:
`block-name__element-name`
-->
<form class="search-form">
<div class="search-form__content">
<!-- Recommended: `search-form__input` or `search-form__content-input` -->
<input class="search-form__content__input">
<!-- Recommended: `search-form__button` or `search-form__content-button` -->
<button class="search-form__content__button">Search</button>
</div>
</form>
The block name defines the namespace,
which guarantees that the elements are dependent on the block block__elem
.
//this block structure is always represented as a flat list of elements in the BEM methodology
.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}
<div class="block">
<div class="block__elem1">
<div class="block__elem2">
<div class="block__elem3"></div>
</div>
</div>
</div>
//The block's structure changes, but the rules for the elements and their names remain the same.
<div class="block">
<div class="block__elem1">
<div class="block__elem2"></div>
</div>
<div class="block__elem3"></div>
</div>
An element is always part of a block, and you shouldn't use it separately from the block.
<!-- Correct. Elements are located inside the `search-form` block -->
<!-- `search-form` block -->
<form class="search-form">
<!-- `input` element in the `search-form` block -->
<input class="search-form__input">
<!-- `button` element in the `search-form` block -->
<button class="search-form__button">Search</button>
</form>
<!--
Incorrect. Elements are located outside of the context of
the `search-form` block
-->
<!-- `search-form` block -->
<form class="search-form">
</form>
<!-- `input` element in the `search-form` block -->
<input class="search-form__input">
<!-- `button` element in the `search-form` block-->
<button class="search-form__button">Search</button>
An element is an optional block component. Not all blocks have elements.
<!-- `search-form` block -->
<div class="search-form">
<!-- `input` block -->
<input class="input">
<!-- `button` block -->
<button class="button">Search</button>
</div>
Modifier
An entity that defines the appearance, state, or behavior of a block or element.
Features:
The modifier name describes its appearance ("What size?" or "Which theme?" and so on — size_s
or theme_islands
),
its state ("How is it different from the others?" — disabled
, focused
, etc.) and its behavior ("How does it behave?" or "How does it respond to the user?" — such as directions_left-top
).
The modifier name is separated from the block or element name by a single underscore _
.
Modifier Boolean
Used when only the presence or absence of the modifier is important, and its value is irrelevant.
For example, disabled
.
If a Boolean modifier is present, its value is assumed to be true.
The structure of the modifier's full name follows the pattern:
block-name_modifier-name
block-name__element-name_modifier-name
<!-- The `search-form` block has the `focused` Boolean modifier -->
<form class="search-form search-form_focused">
<input class="search-form__input">
<!-- The `button` element has the `disabled` Boolean modifier -->
<button class="search-form__button search-form__button_disabled">Search</button>
</form>
Modifier Key-value
Used when the modifier value is important.
For example, "a menu with the islands design theme": menu_theme_islands
.
The structure of the modifier's full name follows the pattern:
block-name_modifier-name_modifier-value
block-name__element-name_modifier-name_modifier-value
<!-- The `search-form` block has the `theme` modifier with the value `islands` -->
<form class="search-form search-form_theme_islands">
<input class="search-form__input">
<!-- The `button` element has the `size` modifier with the value `m` -->
<button class="search-form__button search-form__button_size_m">Search</button>
</form>
<!-- You can't use two identical modifiers with different values simultaneously -->
<form class="search-form
search-form_theme_islands
search-form_theme_lite">
<input class="search-form__input">
<button class="search-form__button
search-form__button_size_s
search-form__button_size_m">
Search
</button>
</form>
A modifier can't be used alone
From the BEM perspective, a modifier can't be used in isolation from the modified block or element.
A modifier should change the appearance, behavior, or state of the entity, not replace it.
<!--
Correct. The `search-form` block has the `theme` modifier with
the value `islands`
-->
<form class="search-form search-form_theme_islands">
<input class="search-form__input">
<button class="search-form__button">Search</button>
</form>
<!-- Incorrect. The modified class `search-form` is missing -->
<form class="search-form_theme_islands">
<input class="search-form__input">
<button class="search-form__button">Search</button>
</form>
Mix
A technique for using different BEM entities on a single DOM node.
Mixes allow you to:
Combine the behavior and styles of multiple entities without duplicating code.
Create semantically new UI components based on existing ones.
<!-- `header` block -->
<div class="header">
<!--
The `search-form` block is mixed with the `search-form` element
from the `header` block
-->
<div class="search-form header__search-form"></div>
</div>
File structure
The component approach adopted in the BEM methodology also applies to projects in the file structure.
The implementations of blocks, elements, and modifiers are divided into independent technology files,
which means we can connect them individually.
Features:
A single block corresponds to a single directory.
The block and the directory have the same name.
For example, the header block is in the header/ directory,
and the menu block is in the menu/ directory.
A block's implementation is divided into separate technology files.
For example, header.css and header.js.
The block directory is the root directory for the subdirectories of its elements and modifiers.
Names of element directories begin with a double underscore (__).
For example, header/__logo/ and menu/__item/.
Names of modifier directories begin with a single underscore (_).
For example, header/_fixed/ and menu/_theme_islands/.
Implementations of elements and modifiers are divided into separate technology files.
For example, header__input.js and header_theme_islands.css.
search-form/ # Directory of the search-form
__input/ # Subdirectory of the search-form__input
search-form__input.css # CSS implementation of the
# search-form__input element
search-form__input.js # JavaScript implementation of the
# search-form__input element
__button/ # Subdirectory of the search-form__button
# element
search-form__button.css
search-form__button.js
_theme/ # Subdirectory of the search-form_theme
# modifier
search-form_theme_islands.css # CSS implementation of the search-form block
# that has the theme modifier with the value
# islands
search-form_theme_lite.css # CSS implementation of the search-form block
# that has the theme modifier with the value
# lite
search-form.css # CSS implementation of the search-form block
search-form.js # JavaScript implementation of the
# search-form block
File structure Flat
Blocks don't have their own directories.
Optional elements and modifiers are implemented in separate files.
blocks/
input_type_search.js
input_type_search.bemhtml.js
input__box.bemhtml.js
input.css
input.js
input.bemhtml.js
button.css
button.js
button.bemhtml.js
button.png
File structure Flex
blocks/
input/
_type/ # type modifier directory
input_type_search.css # Implementation of modifier type
# with value search in CSS technology
__box/ # box element directory
input__box.css
input.css
input.js
button/
button.css
button.js
button.png