CSS naming conventions allow you to write strong, clean, and beautiful code. If you follow the naming rules, you will always know:
- What is the class used for?
- Where the class can be used;
- What other classes is this class associated with.
The naming rules I follow are very simple: I use a hyphen as a separator, and in difficult places I use BEM-like naming.
')
It should be noted that the naming rules themselves will not give much benefit when writing CSS; but they are very useful when viewing the markup.
Hyphen separation
All words in class names must be separated by a hyphen:
.page-head {} .sub-content {}
CamelCase and underscore are not used for classes, the following example is incorrect:
.pageHead {} .sub_content {}
BEM-like naming
For larger interconnected parts of the interface, I use BEM-like class naming.
BEM, that is,
Block, Element, Modifier , is a methodology created by Yandex developers. Despite the fact that BEM is a rather large methodology, at the moment we are only interested in its method of naming elements. Moreover, my naming convention is slightly different from the original BEM: the principles are the same, but the syntax is different.
BEM divides the layout components into three groups:
- Block: main root element.
- Element: part of a block.
- Modifier: option or modification of the block.
Draw an analogy:
.person {} .person__head {} .person--tall {}
At the beginning of the class, the block name is always put, to denote an element, we separate the block name from the element name by two underscores (__), and to denote a modifier we use two hyphens (-).
In the example above, we can see that
.person {}
is a block; he has no ancestors.
.person__head {}
is an element, part of a block; finally,
.person--tall
is a modifier, a kind of
.person {}
block.
Use blocks
A block must be a logical, independent unit. Continuing our example with the class
.person {}
: we cannot create the class
.room__person
, because
.room {}
is an independent unit. In this case, it is worth separating the blocks:
.room {} .room__door {} .room--kitchen {} .person {} .person__head {}
If we need to designate a person inside the room, it would be more appropriate to use such a selector -
.room .person
, which allows you to
.room .person
porridge out of a heap of different incomprehensible elements and blocks.
A more realistic example of the correct use of blocks might look like this:
.page {} .content {} .sub-content {} .footer {} .footer__copyright {}
Each piece of code represents its own block. Incorrect usage example:
.page {} .page__content {} .page__sub-content {} .page__footer {} .page__copyright {}
It is important to be able to distinguish where BEM is worth applying, and where not. As a rule, I use blocks to describe the autonomous parts of the user interface.
Many layers
If we added another element to our
.person {}
block, say,
.person__eye
, we would not need to step back when naming an element, adding the names of the previous elements, right down to the root element. That is, it will be correct to write
.person__eye
, and not
.person__head__eye
.
Adding element modifications
You may need to add variations of elements, this can be done in several ways, depending on how and why these elements should be changed. Again, if a person has blue eyes, then in CSS this can be described as:
.person__eye--blue {}
However, in real projects everything is a bit more complicated. I apologize for such an analogy, but let us imagine a person with a beautiful face. By itself, it is not particularly beautiful, so the best solution would be to add a modifier to the element
.person__face {}
:
.person__face--handsome {}
But what if we want to describe the face of a beautiful person? That is, the person is beautiful in itself, unlike the previous example, and we need to describe his face? This is done as follows:
.person--handsome .person__face {}
This is one of the few cases when we can change an element depending on the modification of the block. If you use Sass, you would get this code:
.person {} .person__face { .person--handsome & {} } .person--handsome {}
Notice that we are not adding a new
.person__face
element inside the
.person--handsome
element
.person--handsome
; instead, we use the Sass parent selector inside the existing
.person__face
selector. This means that all the rules associated with
.person__face
will be in one place, and we will not have to scatter them all over the file. This is a good practice when working with nested code: keep all the necessary styles inside one context (in our case, inside
.person__face
).
Naming in markup
As previously noted, the class naming convention is most useful when working with markup. Take a look at the next piece of markup, not our agreement:
<div class="box profile pro-user"> <img class="avatar image" /> <p class="bio">...</p> </div>
How are the
.box
and
.profile
classes related to each other? How are the
.profile
and
.avatar
related to each other? Are they related at all? Does the
.bio
class
.bio
on the
.pro-user
class? Can I use the
.avatar
class outside of this markup?
When viewing such markup it is very difficult to answer all these questions. Using a naming convention changes things:
<div class="box profile profile--is-pro-user"> <img class="avatar profile__image" /> <p class="profile__bio">...</p> </div>
Now we immediately see which classes are related to each other and how, and which ones are not; we know which classes we cannot use outside of this markup; Finally, we know which classes can be used elsewhere.
Javascript hooks
It is generally unwise to tie JS and CSS code to the same class in the markup, because if you delete or change one class to, for example, change script behavior, you will certainly affect CSS, and vice versa. Much cleaner, more transparent and generally better to tie JS to individual classes.
I came across cases when deleting some classes for the purpose of processing styles, broke all the scripts on the page, and all because the developer did not think and linked the styles with scripts to the same class.
As a rule, developers use a separate class for js, starting with the prefix "js-", for example:
<input type="submit" class="btn js-btn" value="Follow" />
This markup allows you to use
.btn
styles anywhere else without affecting the behavior of
.js-btn
.
data- * attributes
Also, quite often developers use data- * attributes as js-hooks, but this is wrong. data- * attributes, according to the specification, are designed to store data that is not available on the page. data- * attributes are created for storing data, not for binding to js.
Continuing the theme ...
As already mentioned, all the rules presented above are very simple. I urge you not to dwell on what you have learned and read other materials on this topic - this will allow you to get more opportunities for naming classes.
Materials for additional study
Previous part:
CSS GuideLines, part 2. Commenting code