Naming
O nome da class (classe) diz qual papel o elemento cumpre na interface. .button--danger continua correto no dia em que o botão de exclusão deixar de ser vermelho. .red-button obriga alguém a caçar todas as ocorrências no HTML e trocar a classe, ou a conviver com uma classe chamada .red-button num botão laranja.
Conceitos fundamentais
| Conceito | O que é |
|---|---|
| class (classe) | Nome reutilizável posto no elemento por class="...", e alvo do seletor .nome no CSS |
| kebab-case (palavras separadas por hífen) | A forma dos nomes em CSS: product-card |
| BEM (Block Element Modifier · Bloco-Elemento-Modificador) | Convenção block__element--modifier, que amarra a classe ao papel dela dentro do componente |
| block (bloco) | A raiz do componente no BEM: .card, .menu |
| element (elemento) | Uma parte que só existe dentro do bloco: .card__title, .menu__item |
| modifier (modificador) | Uma variante de estado ou aparência do bloco: .button--danger, .menu--open |
| specificity (especificidade) | O peso que o navegador dá a um seletor ao decidir qual regra vence |
| utility class (classe utilitária) | Classe que faz uma coisa só: .text-center, .mt-2 |
O nome vem do papel do elemento, e não da aparência dele
Um nome escolhido pela aparência descreve o CSS de hoje. .blue-header, .big-text, .left-col param de descrever o elemento no primeiro redesenho, e a partir daí quem lê o HTML recebe uma informação falsa sobre o que aquele bloco é.
Um nome escolhido pelo papel atravessa o redesenho intacto. .heading--primary continua sendo o título principal com qualquer cor, e .layout__sidebar continua sendo a barra lateral mesmo se ela mudar de lado.
❌ Ruim: os nomes descrevem cor, tamanho e posição, e travam o design
.blue-header {
color: #1d4ed8;
}
.big-text {
font-size: 2rem;
}
.left-col {
float: left;
width: 30%;
}
.red-alert {
background: red;
color: white;
}
✅ Bom: os nomes descrevem o papel, e o valor visual fica no token
.heading--primary {
color: var(--color-primary);
}
.text--display {
font-size: var(--font-size-display);
}
.layout__sidebar {
width: 30%;
}
.alert--danger {
background: var(--color-danger);
color: var(--color-on-danger);
}
BEM põe a hierarquia dentro do próprio nome da classe
O padrão tem três peças. O bloco é o componente (.card). O elemento é uma parte que só existe dentro dele, escrito com dois sublinhados (.card__title). O modificador é uma variante, escrito com dois hifens (.card--featured).
Com isso, a classe já conta onde ela mora. Quem lê .card__title no HTML sabe que aquele título pertence ao card, sem abrir o CSS. E o seletor no CSS fica com uma classe só, no lugar da corrente .card .title, que amarra o estilo à posição do elemento na marcação e quebra quando alguém move o título de lugar.
❌ Ruim: as classes genéricas só significam algo dentro da corrente de seletores
<div class="card featured">
<img class="image big" />
<h2 class="title">...</h2>
<button class="btn primary">...</button>
</div>
.card .title {
font-size: 1.25rem;
}
.card.featured .title {
font-weight: bold;
}
.card .btn.primary {
background: blue;
}
✅ Bom: cada classe diz a que bloco pertence, e o seletor tem uma classe só
<div class="card card--featured">
<img class="card__image card__image--large" />
<h2 class="card__title">...</h2>
<button class="card__action button button--primary">...</button>
</div>
.card__title {
font-size: 1.25rem;
}
.card--featured .card__title {
font-weight: bold;
}
.button--primary {
background: var(--color-primary);
}
Mantenha a especificidade baixa
Quando duas regras querem estilizar o mesmo elemento, o navegador escolhe a de maior especificidade, e o id pesa muito mais que a classe. Um seletor como #app .container .card h2 vence quase tudo, e é aí que começa o problema.
Para sobrescrever aquela regra em um único lugar, o próximo desenvolvedor precisa escrever um seletor ainda mais pesado, ou apelar para o !important. Alguém depois vai precisar sobrescrever o !important, e a partir daí cada estilo novo carrega o peso acumulado dos anteriores.
Seletor de uma classe só mantém o peso baixo e previsível, e a regra seguinte vence pela ordem no arquivo, que é o comportamento fácil de raciocinar.
❌ Ruim: id encadeado e !important, e a próxima regra precisará pesar mais que os dois
#app .container .card h2 {
font-size: 1.5rem;
}
.nav a:hover {
color: blue !important;
}
✅ Bom: uma classe por seletor, e a ordem do arquivo decide quem vence
.card__title {
font-size: 1.5rem;
}
.nav__link:hover {
color: var(--color-primary);
}
DoDocs v3.7.0 · Desenvolvido por @thiagocajadev · Baseado no trabalho de pmndrs/docs · Poimandres.