O que significa “nomeação consistente” em BEM
BEM (Block, Element, Modifier) é uma convenção de nomes para classes CSS que torna explícito o papel de cada seletor e o escopo em que ele deve atuar. “Nomeação consistente” significa que, ao ler uma classe, você consegue responder rapidamente: (1) qual é o componente principal (bloco), (2) qual parte interna desse componente está sendo estilizada (elemento) e (3) qual variação de aparência/estado está sendo aplicada (modificador). A consistência vem de aplicar as mesmas regras em todo o projeto, evitando sinônimos, abreviações aleatórias e padrões misturados.
Em BEM, a classe é o contrato. Ela descreve a intenção e reduz a necessidade de seletores complexos. Quando a equipe segue o mesmo padrão, o CSS fica mais previsível: você sabe onde procurar estilos, como estender um componente e como evitar “efeitos colaterais” ao criar variações.
Vocabulário BEM: bloco, elemento e modificador
Bloco (Block)
O bloco é a unidade independente de interface: um componente que faz sentido por si só. Exemplos típicos: card, button, modal, navbar, product. Um bloco deve ser nomeado como um substantivo (ou sintagma nominal) que represente o componente, e não sua posição na página.
- Bom:
.card,.product-list,.search-form - Evite:
.left-column,.blue-box,.homepage-card(acopla o componente ao contexto)
Elemento (Element)
Elemento é uma parte interna do bloco, que depende dele para fazer sentido. A sintaxe clássica é bloco__elemento. Elementos não existem “soltos”: se você vê __title sem o bloco, é um sinal de que o nome está incompleto ou que o elemento deveria ser um bloco próprio.
- Exemplos:
.card__title,.card__content,.modal__header,.modal__close - Evite:
.titledentro de muitos componentes (genérico demais) ou.card__leftquando “left” é apenas layout circunstancial
Modificador (Modifier)
Modificador é uma variação do bloco ou do elemento. A sintaxe clássica é bloco--modificador ou bloco__elemento--modificador. Modificadores devem representar uma diferença relevante e previsível: tamanho, aparência, densidade, ênfase, estado ou variante de comportamento visual.
Continue em nosso aplicativo
Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.
ou continue lendo abaixo...Baixar o aplicativo
- Exemplos de bloco:
.button--primary,.card--outlined,.modal--fullscreen - Exemplos de elemento:
.button__icon--left,.card__title--truncate
Um ponto central para variações seguras: o modificador não deve “redefinir” o componente inteiro de forma imprevisível. Ele deve alterar um conjunto pequeno e intencional de propriedades, mantendo o contrato do bloco.
Regras práticas de nomeação (para evitar ambiguidades)
1) Use nomes semânticos, não visuais
Prefira nomes que descrevam função e papel, não cor, pixel ou posição. Isso reduz retrabalho quando o design muda.
- Bom:
.alert--success,.badge--warning - Evite:
.alert--green,.badge--yellow
2) Padronize idioma, separadores e pluralização
Escolha um idioma para os nomes (por exemplo, inglês) e mantenha. Defina também se você usa hífen (product-card) ou camelCase (productCard) para blocos. Em BEM, hífen é o mais comum e combina bem com __ e --.
- Consistente:
.product-card,.product-card__price,.product-card--compact - Inconsistente:
.produtoCard,.product-card__preco,.productCard--compact
3) Evite abreviações não óbvias
Abreviações economizam caracteres, mas custam entendimento. Se a equipe não concorda imediatamente no significado, não use.
- Bom:
.navigation,.navigation__item - Evite:
.nav(pode ser aceitável se for padrão do time),.nvg(opaco)
4) Não encode hierarquia de DOM no nome
BEM já expressa relação bloco-elemento. Evite nomes que dependem da estrutura exata do HTML, como __list-item-link para representar profundidade. Se a profundidade importa, talvez você esteja descrevendo elementos demais ou misturando responsabilidades.
- Preferível:
.menu__iteme dentro dele.menu__link - Evite:
.menu__list__item__link(não é BEM e tende a ficar frágil)
5) Elementos devem ser “partes”, não “variantes”
Se algo é uma variação do componente, use modificador. Se é uma parte estrutural, use elemento. Misturar isso gera confusão e CSS duplicado.
- Parte:
.card__footer - Variação:
.card--with-footer(se a presença/estilo do footer muda o layout do card inteiro)
Variações seguras: como criar modificadores sem quebrar o componente
“Variação segura” é uma variação que não exige conhecer o contexto externo para funcionar e não cria dependências ocultas. Em BEM, isso se traduz em modificadores que:
- Alteram poucas propriedades e de forma previsível.
- Não dependem de seletores de contexto como
.sidebar .buttonpara “consertar” aparência. - Não mudam a estrutura esperada do componente (por exemplo, não exigem que um elemento exista em um lugar específico para o CSS funcionar).
- Não introduzem efeitos colaterais em elementos não relacionados.
Modificadores de “tema” vs. modificadores de “estado”
Uma forma prática de manter variações seguras é separar mentalmente dois tipos comuns:
- Tema/variante visual:
--primary,--secondary,--danger,--outlined,--ghost. - Estado:
--is-loading,--is-disabled,--is-active.
Você pode padronizar prefixos para estados (por exemplo, is-) para deixar claro que são temporários e normalmente controlados por JS ou por atributos. Exemplo:
<button class="button button--primary button--is-loading" type="button">Salvar</button>Note que o estado é um modificador do bloco. Isso evita criar classes genéricas como .is-loading que podem vazar e afetar qualquer coisa.
Evite modificadores que mudam “demais”
Um anti-padrão comum é usar um modificador para transformar um componente em outro. Exemplo: .card--modal ou .button--link quando o resultado se comporta como outro componente com regras próprias. Nesse caso, considere criar um novo bloco (.modal, .link-button) ou um bloco base com composição.
Passo a passo prático: modelando um componente com BEM
Vamos construir um componente de “Card de produto” com variações seguras. O objetivo é mostrar como decidir nomes e como estruturar modificadores sem criar dependências frágeis.
Passo 1: Defina o bloco e seu propósito
O componente representa um produto com imagem, título, preço e ações. Nome do bloco: product-card. Evite card se o projeto tiver muitos tipos de card com contratos diferentes; nesse caso, ser específico ajuda.
<article class="product-card"></article>Passo 2: Liste elementos internos que são partes estáveis
Elementos devem ser partes que provavelmente existirão em qualquer instância do componente (ou, se opcionais, ainda fazem sentido como parte do bloco).
<article class="product-card"> <a class="product-card__media" href="/produto/123"> <img class="product-card__image" src="product.jpg" alt="Tênis"> </a> <div class="product-card__body"> <h3 class="product-card__title">Tênis X</h3> <p class="product-card__price">R$ 199,90</p> </div> <div class="product-card__actions"> <button class="button button--primary" type="button">Comprar</button> </div></article>Repare que o botão é outro bloco (button) sendo composto dentro do product-card. Isso é uma prática saudável: cada bloco mantém seu contrato, e o card apenas organiza.
Passo 3: Crie modificadores de variante (visuais) com escopo claro
Suponha duas variantes: “compacto” e “destaque”. Elas alteram espaçamentos e ênfase, mas não mudam a estrutura.
<article class="product-card product-card--compact">...</article> <article class="product-card product-card--featured">...</article>No CSS, o modificador deve alterar apenas o necessário. Exemplo:
.product-card { display: grid; gap: 12px; padding: 16px; border-radius: 12px;} .product-card--compact { gap: 8px; padding: 12px;} .product-card--featured { border: 2px solid var(--color-accent);}Observe que --featured não redefine layout inteiro; ele adiciona uma borda de destaque. Isso é uma variação segura.
Passo 4: Crie modificadores de estado sem acoplar ao DOM
Agora um estado: indisponível. Esse estado pode afetar imagem, preço e botão, mas deve ser controlado pelo bloco, não por seletores externos.
<article class="product-card product-card--is-unavailable">...</article>.product-card--is-unavailable { opacity: 0.6;} .product-card--is-unavailable .product-card__actions { pointer-events: none;}Esse exemplo usa um seletor descendente dentro do próprio bloco, o que é aceitável quando você está restringindo o efeito a elementos do mesmo bloco. O cuidado é não criar dependência de contexto externo; aqui, tudo permanece dentro do contrato do product-card.
Passo 5: Quando o modificador é do elemento (e não do bloco)
Algumas variações são locais a um elemento. Exemplo: título truncado em uma linha apenas em certas listagens. Em vez de criar um modificador do bloco que afeta o título, você pode modificar o próprio elemento:
<h3 class="product-card__title product-card__title--truncate">Tênis X Edição Limitada...</h3>.product-card__title--truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis;}Isso é seguro porque a variação é claramente local e não altera o restante do componente.
Como lidar com “variações por contexto” sem quebrar BEM
Um problema recorrente é precisar de um componente com aparência diferente quando usado em uma área específica (ex.: dentro de um header, dentro de um sidebar). A abordagem frágil é escrever CSS do tipo .sidebar .product-card { ... }, porque isso cria dependência do local e dificulta reutilização.
Em BEM, prefira uma destas estratégias:
- Modificador explícito: o contexto aplica uma classe de modificador no componente, como
product-card--in-sidebar. Isso torna a dependência visível no HTML. - Bloco “wrapper” com composição: crie um bloco para o contexto (ex.:
sidebar) e, se necessário, use uma classe de utilidade ou um modificador no componente para ajustes mínimos. - Nova variante do componente: se o “mesmo” componente muda muito, é sinal de que são dois componentes diferentes. Crie um novo bloco com contrato próprio.
Exemplo com modificador explícito:
<aside class="sidebar"> <article class="product-card product-card--in-sidebar">...</article></aside>O nome --in-sidebar é aceitável quando o ajuste é realmente contextual e pequeno. Se começar a acumular muitos contextos (--in-header, --in-footer, --in-modal), reavalie o design do componente.
Checklist de consistência: decisões que o time deve padronizar
Para que BEM funcione em projetos reais, é útil transformar decisões em regras simples. Abaixo um checklist que você pode adotar como padrão interno.
Formato e caracteres
- Blocos em minúsculas com hífen:
product-card. - Elemento com
__:product-card__title. - Modificador com
--:product-card--featured. - Sem underscores simples (
_) para não confundir com__.
Estados
- Estados como modificadores do bloco:
--is-loading,--is-disabled,--is-open. - Evitar estados globais genéricos (
.is-open) a menos que exista uma camada de utilitários bem definida e controlada.
Variações
- Modificadores descrevem “o que muda” (ex.:
--compact,--outlined), não “como é implementado” (ex.:--gridse o usuário não precisa saber disso). - Evitar modificadores com múltiplos significados (ex.:
--special,--new).
Elementos opcionais
- Elementos opcionais podem existir, mas o bloco não deve quebrar se eles não estiverem presentes.
- Se um elemento opcional vira “um componente dentro do componente” com regras próprias, considere promovê-lo a bloco (composição).
Armadilhas comuns e como corrigir
Armadilha 1: “Elemento de elemento”
Em BEM clássico, não existe block__element__subelement. Se você sente necessidade disso, geralmente é um sinal de que:
- Você está descrevendo a estrutura do DOM em vez de papéis.
- Um elemento complexo deveria ser um bloco interno.
Exemplo de correção por composição:
<div class="card"> <div class="card__header"> <div class="user-badge"> <img class="user-badge__avatar" ...> <span class="user-badge__name">...</span> </div> </div></div>Armadilha 2: Modificador usado como bloco
Exemplo: criar .button--primary e usar sem .button. Isso quebra o contrato, porque o modificador pressupõe a base do bloco.
- Correto:
class="button button--primary" - Incorreto:
class="button--primary"
Se você quer uma classe única para o caso, então primary-button seria outro bloco (mas normalmente é melhor manter o padrão de base + modificador).
Armadilha 3: Modificadores em cascata que viram “combinações explosivas”
Quando você cria muitos modificadores que interagem entre si, o número de combinações cresce e fica difícil garantir consistência. Exemplo: --compact + --featured + --with-badge + --horizontal. Para manter variações seguras:
- Defina quais modificadores podem coexistir.
- Evite modificadores que mudam o “tipo” do componente (ex.: vertical vs horizontal) se isso exigir reescrever muitos estilos; considere variantes separadas ou um novo bloco.
- Quando coexistirem, mantenha regras simples e previsíveis (por exemplo,
--compactsó mexe em espaçamento).
Armadilha 4: Nomes que viram “lixeira”
Classes como --custom, --alt, --v2 geralmente indicam falta de critério. Troque por nomes que expliquem intenção:
--alt→--outlinedou--subtle--v2→--dense,--compact,--with-icon(o que realmente mudou?)
Guia rápido de decisão: isso é bloco, elemento ou modificador?
Use estas perguntas para decidir rapidamente:
- É reutilizável sozinho e tem significado independente? Então é um bloco.
- É uma parte interna que só faz sentido dentro do componente? Então é um elemento.
- É uma variação de aparência/estado do bloco ou do elemento, sem criar um “novo componente”? Então é um modificador.
Exemplo aplicado:
modal(bloco)modal__header(elemento)modal--fullscreen(modificador do bloco)modal__close--hidden(modificador do elemento, se for uma variação local)
Exemplo completo: componente de formulário com variações seguras
Agora um exemplo que costuma gerar CSS inconsistente: campo de texto com ícone, mensagem de erro e tamanhos.
<div class="field field--md"> <label class="field__label" for="email">E-mail</label> <div class="field__control"> <span class="field__icon" aria-hidden="true"></span> <input class="field__input" id="email" type="email"> </div> <p class="field__message"></p></div>Variações seguras:
- Tamanho:
field--sm,field--md,field--lg(muda padding, font-size, altura do input). - Estado de erro:
field--is-invalid(muda borda e mostra mensagem). - Sem ícone:
field--no-icon(ajusta padding do input).
<div class="field field--sm field--is-invalid"> ... <p class="field__message">E-mail inválido</p></div>Note que o estado de erro está no bloco, porque afeta múltiplos elementos internos. Já uma variação como “truncar mensagem” poderia ser um modificador do elemento field__message--truncate se fosse algo local.