Telles Logo
Pular para o conteúdo
Ver todos os artigos
ago 16, 2023
·
views
·
likes
·
10 min

Arquitetura de estilos (CSS)

Comparação das principais abordagens de arquitetura de CSS: CSS Básico, BEM e ACSS - Descubra qual é a melhor para o seu projeto

Se você já leu a comparação de arquiteturas CSS, já sabe o que é CSS Básico, BEM e CSS Atômico — as vantagens, desvantagens e quando escolher cada um. Este artigo pega de onde aquele deixou: o que acontece na prática, quando um time precisa mover código de uma metodologia para outra, quando faz sentido misturar abordagens, e como a escolha de nomenclatura molda a colaboração no dia a dia.


Como a nomenclatura afeta a colaboração

Antes de qualquer comparação de sintaxe, vale entender por que isso importa em equipe. Convenções de nomenclatura não são apenas estética — elas são o protocolo de comunicação entre devs que não necessariamente lêem o CSS um do outro.

Considere três devs trabalhando num mesmo projeto sem convenção acordada:

/* Dev A */
.card-title { font-size: 18px; }
 
/* Dev B */
.card .title { font-size: 20px; }
 
/* Dev C */
.productCard__heading { font-size: 18px; }

Três meses depois, ninguém sabe qual classe usar quando adiciona um novo card. Pior: as três existem no bundle, com valores diferentes, potencialmente se sobrescrevendo dependendo da ordem de importação.

O custo oculto da inconsistência

Projetos sem convenção acumulam "CSS morto" — regras que ninguém ousa deletar por medo de quebrar algo. A inconsistência de nomenclatura é a principal razão pela qual devs deixam CSS legado intocado por anos. Estudos de codebase em equipes de médio porte mostram que entre 30% e 60% das regras CSS de projetos sem convenção se tornam inacessíveis (não referenciadas em nenhum HTML ativo) ao longo do tempo.


Convenções de nomenclatura por tipo de componente

A melhor forma de internalizar como cada abordagem funciona na prática é ver o mesmo conjunto de componentes escritos nas três metodologias. Aqui estão quatro tipos comuns — formulário, navegação, card e modal:

/* CSS Básico */
.form { display: flex; flex-direction: column; gap: 16px; }
.form label { font-size: 14px; color: #6c757d; }
.form input { border: 1px solid #dee2e6; border-radius: 4px; padding: 8px 12px; }
.form input.error { border-color: #dc3545; }
.form button { background: #0d6efd; color: white; padding: 10px 24px; }
 
/* BEM */
.form { display: flex; flex-direction: column; gap: 16px; }
.form__label { font-size: 14px; color: #6c757d; }
.form__input { border: 1px solid #dee2e6; border-radius: 4px; padding: 8px 12px; }
.form__input--error { border-color: #dc3545; }
.form__submit { background: #0d6efd; color: white; padding: 10px 24px; }
 
/* ACSS / Tailwind (no HTML) */
/* <form class="flex flex-col gap-4"> */
/* <label class="text-sm text-gray-500"> */
/* <input class="border border-gray-300 rounded px-3 py-2 focus:border-blue-500"> */
/* <input class="border border-red-500 rounded px-3 py-2"> (estado de erro) */
/* <button class="bg-blue-600 text-white px-6 py-2.5 rounded hover:bg-blue-700"> */

O padrão que emerge: o BEM torna a estrutura do componente legível sem abrir o arquivo CSS. Ao ver .modal__close no HTML, você sabe imediatamente que esse elemento pertence ao componente modal. Com CSS Básico ou até com ACSS, essa relação é mais implícita.


Comparação ao vivo — o mesmo componente nas três abordagens

Abordagem CSS
Variante
Preview
Produto Exemplo
R$ 99,90
Classes aplicadas
card.card
title.card__title
price.card__price
button.card__button
CSS — BEM (Padrão)
.card { border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px; background: #fff; }
.card__title { font-size: 18px; font-weight: 600; color: #111827; margin-bottom: 4px; }
.card__price { color: #16a34a; font-weight: 700; font-size: 20px; margin-bottom: 12px; }
.card__button { background: #3b82f6; color: white; padding: 8px 16px; border-radius: 4px; border: none; cursor: pointer; font-weight: 600; }
.card { border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px; background: #fff; }
.card__title { font-size: 18px; font-weight: 600; color: #111827; margin-bottom: 4px; }
.card__price { color: #16a34a; font-weight: 700; font-size: 20px; margin-bottom: 12px; }
.card__button { background: #3b82f6; color: white; padding: 8px 16px; border-radius: 4px; border: none; cursor: pointer; font-weight: 600; }

Como migrar de CSS Básico para BEM

Migrar um projeto inteiro de uma vez é arriscado e raramente vale a pena. A estratégia mais segura é a migração incremental por componente — você adota BEM nos componentes novos e refatora os antigos gradualmente, começando pelos mais críticos ou mais frequentemente modificados.

Antes: CSS Básico típico

<div class="card">
  <img class="image" src="produto.jpg" alt="Produto" />
  <div class="info">
    <h2 class="title">Tênis Runner Pro</h2>
    <p class="price">R$ 299,90</p>
    <button class="button disabled">Esgotado</button>
  </div>
</div>
.card { border: 1px solid #ddd; border-radius: 8px; overflow: hidden; }
.image { width: 100%; height: 200px; object-fit: cover; }
.info { padding: 16px; }
.title { font-size: 18px; font-weight: 600; }
.price { color: #28a745; font-size: 20px; font-weight: 700; }
.button { background: #007bff; color: white; padding: 10px 20px; border: none; cursor: pointer; }
.button.disabled { opacity: 0.5; cursor: not-allowed; }

O problema: .title, .price e .button são classes genéricas. Se outro componente do projeto também usa .title, há conflito garantido ou dependência da ordem de importação.

Depois: BEM

<div class="product-card">
  <img class="product-card__image" src="produto.jpg" alt="Produto" />
  <div class="product-card__info">
    <h2 class="product-card__title">Tênis Runner Pro</h2>
    <p class="product-card__price">R$ 299,90</p>
    <button class="product-card__button product-card__button--disabled">Esgotado</button>
  </div>
</div>
.product-card { border: 1px solid #ddd; border-radius: 8px; overflow: hidden; }
.product-card__image { width: 100%; height: 200px; object-fit: cover; }
.product-card__info { padding: 16px; }
.product-card__title { font-size: 18px; font-weight: 600; }
.product-card__price { color: #28a745; font-size: 20px; font-weight: 700; }
.product-card__button { background: #007bff; color: white; padding: 10px 20px; border: none; cursor: pointer; }
.product-card__button--disabled { opacity: 0.5; cursor: not-allowed; }

Agora .product-card__title nunca entra em conflito com .hero__title ou qualquer outro título do projeto. O bloco é completamente autossuficiente.

  • Comece pelos componentes com mais bugs de CSS

    Os componentes que mais sofrem com estilos quebrados são geralmente os que têm mais conflitos de nomenclatura. Priorizá-los na migração tem impacto imediato.

  • Use um prefixo de bloco descritivo

    .card é genérico; .product-card e .article-card são específicos. Um bloco BEM bem nomeado já documenta seu domínio.

  • Não migre e use a nomenclatura antiga ao mesmo tempo

    Ter .card e .product-card no mesmo componente durante a migração cria confusão. Decida um ponto de corte e mantenha separação clara.

  • Atualize os testes de snapshot se existirem

    Mudar nomes de classe quebra snapshots de testes de componente. Planeje para atualizar esses testes junto com a refatoração de CSS.


Abordagens híbridas: BEM + utilitários

Um equívoco comum é tratar as metodologias como mutuamente exclusivas. Na prática, muitos times adotam uma abordagem híbrida que combina o melhor de cada uma: BEM para a estrutura e semântica dos componentes, utilitários para layout e espaçamento.

A lógica é simples: o BEM é excelente para definir o que um componente é e como ele se comporta internamente. Classes utilitárias como as do Tailwind são excelentes para posicionar e espaçar componentes no layout.

<!-- Componente interno: BEM -->
<!-- Layout externo: utilitários -->
<section class="flex flex-col gap-8 px-6 py-12">
  <div class="product-card">
    <img class="product-card__image" src="produto.jpg" alt="Produto" />
    <div class="product-card__info">
      <h2 class="product-card__title">Tênis Runner Pro</h2>
      <p class="product-card__price">R$ 299,90</p>
    </div>
  </div>
</section>
/* O componente product-card usa BEM puro */
.product-card { border: 1px solid #dee2e6; border-radius: 8px; overflow: hidden; }
.product-card__image { width: 100%; aspect-ratio: 16/9; object-fit: cover; }
.product-card__info { padding: 16px; }
.product-card__title { font-size: 18px; font-weight: 600; }
.product-card__price { color: #28a745; margin-top: 4px; }
 
/* O layout usa Tailwind — sem CSS customizado necessário */
/* flex, flex-col, gap-8, px-6, py-12 vêm do Tailwind */
Onde traçar a linha entre BEM e utilitários

Uma heurística que funciona bem na prática: use BEM para tudo que faz parte da identidade visual do componente (cores, tipografia, bordas, estados), e use utilitários para tudo que é posicionamento relativo ao contexto (margin, padding externo, flex/grid de container). Essa divisão mantém os componentes BEM portáveis — você os move para qualquer contexto e os utilitários do wrapper cuidam do layout.

🧱BEM: estrutura e identidade

Cor, tipografia, borda, sombra, estados interativos (hover, focus, disabled). Tudo que define o que o componente é.

Utilitários: posição e contexto

Margin externa, padding de container, flex/grid do layout envolvente. Tudo que define onde o componente está.

📏A regra prática

Se o estilo muda dependendo de onde o componente aparece, é utilitário. Se o estilo é sempre o mesmo independente do contexto, é BEM.


O que a escolha diz sobre sua equipe

No fim, a metodologia de CSS que um time escolhe reflete como ele pensa sobre manutenibilidade a longo prazo. Não existe escolha errada desde que seja uma escolha consciente e consistente.

  • Documente a convenção em algum lugar acessível

    Um STYLEGUIDE.md simples com exemplos de BEM ou uma seção no Storybook vale mais do que qualquer ferramenta de lint. A documentação que ninguém lê não existe.

  • Use linting para reforçar a convenção

    O stylelint com plugins como stylelint-selector-bem-pattern automatiza a verificação de nomenclatura BEM. Erros de convenção detectados no CI nunca chegam ao review.

  • Reavalie ao mudar o tamanho do time

    Uma convenção que funciona para 2 devs pode não escalar para 10. O momento de revisar a arquitetura CSS é quando o time cresce — não quando já acumulou três anos de dívida técnica.

  • Evite migrar por modismo

    "Todos estão usando Tailwind" não é razão suficiente para migrar um projeto com 50 mil linhas de BEM estável. O custo de migração precisa ser comparado ao ganho real para aquele projeto específico.

As minhas notas

Selecione um trecho e use Destacar no menu (somente neste aparelho).

Artigos relacionados