O que são “exemplos progressivos antes/depois” e por que eles funcionam
Refatorar CSS em projetos reais raramente é um “big bang”. O que funciona melhor é uma sequência de mudanças pequenas, verificáveis e reversíveis: você pega um trecho problemático, cria um “antes” (como está hoje), define um “depois” (como deve ficar), e aplica uma refatoração guiada por regras claras. “Exemplos progressivos antes/depois” são exatamente isso: uma trilha de refatoração em etapas, onde cada etapa melhora um aspecto (seletores, camadas, componentes) sem exigir reescrever o projeto inteiro.
O objetivo não é “deixar bonito”, e sim reduzir risco. Cada passo deve: (1) diminuir a chance de efeitos colaterais, (2) tornar o CSS mais previsível, (3) facilitar a evolução do componente e (4) permitir que você pare no meio sem quebrar o produto. Para isso, você vai trabalhar em três frentes que se reforçam: refatoração de seletores (menos fragilidade), alinhamento com camadas (menos conflitos) e consolidação de componentes (menos duplicação e variações inconsistentes).
Preparação: como escolher o alvo e definir critérios de sucesso
Escolha um alvo com impacto e fronteiras claras
Prefira um componente/área com: alta recorrência (aparece em várias telas), histórico de bugs visuais, muitas variações improvisadas ou CSS com seletores longos e dependentes de estrutura. Exemplos comuns: cabeçalho com navegação, card de produto, formulário de login, lista de resultados, modal.
Defina o “contrato visual” antes de mexer
Antes de alterar qualquer linha, registre o comportamento esperado: estados (hover, focus, disabled), variações (tamanho/tema), responsividade (breakpoints relevantes) e dependências (ícones, imagens, slots). Se possível, capture screenshots e anote medidas importantes (altura, espaçamentos, alinhamentos). Isso vira seu checklist de regressão manual.
Critérios práticos de sucesso
- O componente não depende de seletores de tag/ID ou de profundidade de DOM para funcionar.
- As variações são expressas por classes (modificadores/estados) e não por “gambiarras” de cascata.
- O CSS do componente pode ser movido de lugar sem quebrar (desde que respeite a camada).
- Novas variações exigem adicionar classes e regras locais, não “caçar” conflitos no projeto.
Exemplo 1 (progressivo): refatoração guiada de seletores
Neste exemplo, o problema central é a fragilidade dos seletores: regras dependem de tags, IDs, ordem de elementos e contexto. O resultado típico é: qualquer ajuste no HTML quebra o estilo, e qualquer estilo novo pode “vazar” para outros lugares.
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
Antes: seletores acoplados à estrutura e ao contexto
/* CSS legado (exemplo) */
#checkout .content .box ul li a {
color: #0a58ca;
text-decoration: none;
}
#checkout .content .box ul li a:hover {
text-decoration: underline;
}
#checkout .content .box ul li .badge {
background: #dc3545;
color: #fff;
border-radius: 999px;
padding: 2px 8px;
font-size: 12px;
}
#checkout .content .box ul li.active a {
font-weight: 700;
}Problemas típicos aqui: (1) especificidade alta por causa de ID e cadeia longa, (2) dependência de ul li a (se virar div ou mudar a estrutura, quebra), (3) “active” depende do li e não do item em si, (4) difícil reaproveitar fora do checkout.
Passo 1: criar uma classe de componente e “espelhar” o estilo sem remover o legado
O primeiro passo seguro é introduzir classes novas no HTML e escrever regras equivalentes com seletores curtos. Você não precisa apagar o legado ainda; apenas garanta que o novo CSS consiga assumir o controle quando as classes estiverem presentes.
<nav class="c-steps" aria-label="Etapas">
<ul class="c-steps__list">
<li class="c-steps__item is-active">
<a class="c-steps__link" href="#">Entrega</a>
<span class="c-steps__badge">1</span>
</li>
</ul>
</nav>/* Novo CSS (primeira aproximação) */
.c-steps__link {
color: var(--color-link, #0a58ca);
text-decoration: none;
}
.c-steps__link:hover {
text-decoration: underline;
}
.c-steps__badge {
background: var(--color-danger, #dc3545);
color: var(--color-on-danger, #fff);
border-radius: 999px;
padding: 2px 8px;
font-size: 12px;
}
.c-steps__item.is-active .c-steps__link {
font-weight: 700;
}Note que o único seletor “composto” é o estado .is-active afetando o link dentro do item. Isso é aceitável porque está dentro do escopo do componente e não depende de tags nem de profundidade arbitrária.
Passo 2: reduzir dependência de estrutura (evitar “.item .link” quando possível)
Quando o estado é uma característica do link (e não do item), você pode mover o estado para o próprio elemento-alvo. Isso reduz dependência de hierarquia e facilita reuso.
<li class="c-steps__item">
<a class="c-steps__link is-active" href="#">Entrega</a>
<span class="c-steps__badge">1</span>
</li>.c-steps__link.is-active {
font-weight: 700;
}Esse ajuste é pequeno, mas costuma eliminar uma categoria inteira de bugs: “o estado está no lugar errado”. Em projetos grandes, estados em contêineres geram efeitos colaterais quando o contêiner passa a agrupar mais coisas.
Passo 3: substituir o legado com segurança (estratégia de convivência)
Agora que o componente está “autossuficiente”, você pode remover gradualmente os seletores antigos. Uma abordagem prática é: (1) localizar onde o HTML já recebeu as novas classes, (2) remover regras antigas apenas quando não houver mais instâncias dependentes delas. Se você não consegue remover de imediato, pelo menos “congele” o legado: evite adicionar novas regras nele e direcione qualquer evolução para o novo componente.
Exemplo 2 (progressivo): refatoração guiada por camadas (realocação e contenção de impacto)
Às vezes o CSS até tem classes razoáveis, mas está no lugar errado: regras de componente misturadas com utilitários, overrides globais dentro de arquivos de página, ou estilos “rápidos” que viram dependência. O sintoma é clássico: “mudei um botão e quebrou o card em outra tela”. O problema não é só seletor; é camada e ordem.
Antes: estilos de página sobrescrevendo componente
/* arquivo: pages/checkout.css */
.button {
padding: 14px 18px;
border-radius: 10px;
}
.checkout .button {
background: #198754;
}
.checkout .summary .button {
width: 100%;
}Aqui, um estilo de página altera o “contrato” do componente .button (padding e radius), e ainda cria variações contextuais (.checkout .button) que não existem em outros lugares. Isso torna impossível prever como o botão vai se comportar fora do checkout.
Passo 1: identificar o que é “variação do componente” vs “regra de layout da página”
- Variação do componente: cor/tema, tamanho, densidade, estados. Deve morar no CSS do componente.
- Regra de layout: largura 100%, alinhamento, espaçamento em relação a vizinhos. Deve morar no contexto (objeto/layout/página), mas sem alterar o núcleo do componente.
Passo 2: mover variações para o componente e trocar contexto por modificador
/* arquivo: components/button.css */
.c-button {
padding: 10px 14px;
border-radius: 8px;
}
.c-button--success {
background: var(--color-success, #198754);
color: var(--color-on-success, #fff);
}<button class="c-button c-button--success">Continuar</button>Você remove a necessidade de .checkout .button para cor. O checkout apenas escolhe uma variação existente do botão.
Passo 3: manter regras de layout no contexto sem “mutar” o componente
/* arquivo: pages/checkout.css (ou um layout local) */
.checkout__primaryAction {
width: 100%;
}
/* HTML */
<div class="checkout__primaryAction">
<button class="c-button c-button--success">Continuar</button>
</div>O botão continua sendo botão. O container decide que, naquela página, a ação primária ocupa a largura total. Essa separação reduz conflitos e facilita reuso.
Passo 4: criar “pontos de extensão” explícitos quando o contexto precisa influenciar
Em alguns casos, o contexto precisa ajustar algo do componente (ex.: densidade em uma sidebar). Em vez de sobrescrever propriedades arbitrárias, crie uma variação explícita.
/* components/button.css */
.c-button--block {
display: inline-flex;
width: 100%;
justify-content: center;
}<button class="c-button c-button--success c-button--block">Continuar</button>Isso evita que cada página invente seu próprio “botão full width” com regras diferentes.
Exemplo 3 (progressivo): refatoração de um componente real com antes/depois em etapas
Agora um caso mais completo: um card de produto que cresceu com variações improvisadas. O objetivo é sair de um CSS cheio de exceções para um componente com partes claras, variações controladas e estados previsíveis.
Antes: card com seletores genéricos e variações por contexto
/* legado */
.card {
border: 1px solid #ddd;
padding: 16px;
background: #fff;
}
.card h3 {
font-size: 18px;
margin: 0 0 8px;
}
.card .price {
color: #198754;
font-weight: 700;
}
.home .card {
border-radius: 12px;
}
.search .card {
display: flex;
gap: 12px;
}
.search .card img {
width: 96px;
height: 96px;
object-fit: cover;
}O card muda de forma dependendo da página (.home, .search). Além disso, estiliza tags (h3) e classes genéricas (.price) que podem existir em outros componentes.
Passo 1: “congelar” o legado e introduzir um novo card com nomes explícitos
Você pode manter o legado funcionando enquanto cria um novo componente em paralelo. A migração pode ser feita tela a tela.
<article class="c-productCard">
<a class="c-productCard__media" href="#">
<img class="c-productCard__image" src="product.jpg" alt="Produto">
</a>
<div class="c-productCard__body">
<h3 class="c-productCard__title">Tênis X</h3>
<p class="c-productCard__price">R$ 199,90</p>
</div>
</article>/* components/product-card.css */
.c-productCard {
border: 1px solid var(--color-border, #ddd);
padding: 16px;
background: var(--color-surface, #fff);
}
.c-productCard__title {
font-size: 18px;
margin: 0 0 8px;
}
.c-productCard__price {
color: var(--color-success, #198754);
font-weight: 700;
margin: 0;
}Passo 2: transformar variações por página em modificadores do componente
Em vez de .home .card e .search .card, crie variações explícitas: por exemplo, --rounded e --horizontal. O nome deve refletir o efeito, não a página.
/* components/product-card.css */
.c-productCard--rounded {
border-radius: 12px;
}
.c-productCard--horizontal {
display: flex;
gap: 12px;
align-items: flex-start;
}
.c-productCard--horizontal .c-productCard__image {
width: 96px;
height: 96px;
object-fit: cover;
}<article class="c-productCard c-productCard--horizontal">...</article>Perceba que ainda existe um seletor composto no modificador horizontal para ajustar a imagem. Isso é aceitável porque é uma variação do próprio componente e permanece dentro do escopo do card.
Passo 3: reduzir “efeitos colaterais” com slots e elementos opcionais
Cards reais ganham badges, avaliações, botões, parcelas, frete etc. O erro comum é “pendurar” estilos em classes genéricas (.badge, .rating) e deixar o card depender de componentes externos sem contrato. Uma alternativa é criar slots/elementos do card que acomodem conteúdo variável.
<article class="c-productCard c-productCard--horizontal">
<a class="c-productCard__media" href="#">
<img class="c-productCard__image" src="product.jpg" alt="Produto">
<span class="c-productCard__flag">Frete grátis</span>
</a>
<div class="c-productCard__body">
<h3 class="c-productCard__title">Tênis X</h3>
<div class="c-productCard__meta">
<span class="c-productCard__rating">4,8</span>
<span class="c-productCard__reviews">(321)</span>
</div>
<p class="c-productCard__price">R$ 199,90</p>
<div class="c-productCard__actions">
<button class="c-button c-button--success">Comprar</button>
</div>
</div>
</article>.c-productCard__meta {
display: flex;
gap: 8px;
align-items: baseline;
margin-bottom: 8px;
}
.c-productCard__flag {
position: absolute;
top: 8px;
left: 8px;
background: var(--color-surface, #fff);
border: 1px solid var(--color-border, #ddd);
border-radius: 999px;
padding: 2px 8px;
font-size: 12px;
}
.c-productCard__media {
position: relative;
display: block;
}O card passa a ter “lugares” para conteúdo, e o CSS fica responsável por layout interno. Componentes externos (como o botão) entram no slot de ações sem o card precisar conhecer detalhes do botão.
Passo 4: introduzir estados sem depender de página ou JS “mágico”
Estados comuns: selecionado, indisponível, carregando. A refatoração progressiva recomenda criar classes de estado previsíveis e aplicá-las no bloco do componente, para que o comportamento seja fácil de localizar.
.c-productCard.is-disabled {
opacity: 0.6;
}
.c-productCard.is-disabled .c-productCard__actions {
pointer-events: none;
}<article class="c-productCard is-disabled">...</article>Se o estado afeta o componente inteiro, aplicar no bloco tende a ser mais claro. Se afeta apenas um elemento (ex.: link ativo), aplicar no próprio elemento pode ser melhor. A regra prática é: estado no menor escopo que represente corretamente o comportamento.
Checklist de refatoração guiada (para usar em qualquer antes/depois)
Seletores
- Trocar seletores baseados em tag/estrutura por classes do componente.
- Evitar cadeias longas; preferir seletores diretos do bloco/elemento.
- Estados e variações devem ser explícitos (classes), não dependentes de contexto de página.
- Quando precisar de seletor composto, limitar ao escopo do componente e justificar (ex.: modificador que ajusta um elemento interno).
Camadas
- Não permitir que páginas redefinam o “núcleo” de componentes (padding, radius, tipografia base do componente).
- Regras de layout do contexto devem envolver o componente, não reescrevê-lo.
- Quando o contexto precisa de comportamento recorrente, promover para uma variação/modificador do componente.
Componentes
- Mapear partes internas como elementos claros (título, mídia, meta, ações).
- Criar slots/containers internos para conteúdo variável em vez de depender de classes genéricas.
- Adicionar estados com impacto previsível e escopo correto.
- Migrar por instâncias: introduzir novo componente, aplicar em uma tela, validar, expandir.
Estratégia prática de migração em etapas (sem reescrever tudo)
1) Convivência controlada
Durante a migração, é comum ter legado e novo CSS coexistindo. Para evitar confusão, estabeleça uma regra operacional: qualquer mudança nova deve ser feita no componente novo, e o legado só recebe correções críticas. Isso impede que o legado continue crescendo.
2) Migração por “ilhas”
Escolha uma rota: migrar por página (checkout inteiro) ou por componente (todos os cards). Em projetos grandes, migrar por componente costuma dar mais retorno, porque você elimina duplicações em várias telas. Migrar por página pode ser útil quando a página tem muitas particularidades e você quer estabilizá-la primeiro.
3) Remoção do legado com busca por uso
Quando um componente novo já cobre todas as instâncias, remova o CSS antigo. Se não for possível remover, isole: mova o legado para um arquivo claramente marcado e evite importá-lo globalmente quando não necessário. A meta é reduzir a superfície de impacto do legado até ele desaparecer.
4) Regressão visual focada
A cada etapa, valide o checklist de contrato visual: estados, variações e responsividade. Em refatoração progressiva, o “depois” não precisa ser perfeito de primeira; ele precisa ser estável e evolutivo. Ajustes finos podem vir em etapas seguintes, desde que o componente já tenha fronteiras claras.