2

Cascade Layers do CSS: Como Dominar a Especificidade Sem Gambiarras

O problema que !important nunca resolveu

Especificidade no CSS funciona como um sistema de pontuação: IDs vencem classes, classes vencem elementos, inline vence tudo. Quando dois seletores competem, o mais específico ganha. O mecanismo é previsível, mas a previsibilidade se perde quando o projeto cresce e múltiplas origens de estilo colidem: reset global, design system, estilos de componente, overrides de página, CSS de terceiros.

A reação instintiva é escalar especificidade. Adicionar um ID. Empilhar classes. Quando nada funciona, !important. E quando dois !important colidem, a especificidade volta a decidir, só que agora dentro de uma dimensão mais difícil de depurar.

Cascade Layers (@layer) atacam esse problema em uma camada acima da especificidade. Literalmente. Elas criam um nível de prioridade na cascata que é avaliado antes da especificidade dos seletores. Isso significa que um seletor de elemento simples (p) em uma camada de alta prioridade vence um seletor de ID (#hero .title) em uma camada de baixa prioridade, sem nenhum !important.

Como a cascata funciona com layers

A cascata do CSS resolve conflitos nesta ordem (simplificada):

  1. Origem e !important (user-agent, user, author)
  2. Contexto (inline style, Shadow DOM)
  3. Camada (layer) ← novo nível
  4. Especificidade do seletor
  5. Ordem de aparição no código

Layers se encaixam entre contexto e especificidade. Quando dois seletores estão em camadas diferentes, a camada de maior prioridade vence, independentemente de quantos IDs o seletor perdedor tenha.

A ordem de prioridade das camadas é definida pela ordem de declaração: a última camada declarada tem maior prioridade. E estilos fora de qualquer camada (unlayered) vencem todas as camadas.

/* A ordem aqui define prioridade: reset < base < components < utilities */
/* utilities vence components, que vence base, que vence reset */
@layer reset, base, components, utilities;

Declarando e usando camadas

Existem três formas de criar e popular uma camada.

Declaração antecipada com preenchimento posterior

/* Declara a ordem de prioridade no topo do arquivo principal */
@layer reset, base, components, utilities;

/* Preenche cada camada onde quiser, inclusive em arquivos separados */
@layer reset {
  *,
  *::before,
  *::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
}

@layer base {
  body {
    font-family: "Inter", system-ui, sans-serif;
    line-height: 1.6;
    color: #1a1a1a;
  }

  /* Seletor simples de elemento: funciona porque a camada controla prioridade */
  a {
    color: #2563eb;
    text-decoration-thickness: 1.5px;
  }
}

Declaração inline (camada criada e preenchida ao mesmo tempo)

@layer components {
  .card {
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 1.5rem;
    background: #fff;
  }

  .card-header {
    font-size: 1.25rem;
    font-weight: 600;
    margin-bottom: 0.75rem;
  }
}

Importação direta em uma camada

/* CSS de terceiro entra na camada de menor prioridade */
/* Qualquer estilo seu em camadas posteriores vence automaticamente */
@import url("vendor/datepicker.css") layer(vendor);

@layer vendor, reset, base, components, utilities;

Essa terceira forma é a mais poderosa para lidar com CSS de bibliotecas externas. Todo o CSS importado fica confinado na camada vendor, e qualquer estilo seu em components ou utilities vence sem precisar inflar seletores.

Arquitetura de camadas para projetos reais

Uma estrutura que funciona para a maioria dos projetos frontend com design system:

/* styles/layers.css */
/* Arquivo de entrada: define a ordem canônica de camadas */
@import url("./vendor.css") layer(vendor);

@layer vendor, reset, tokens, base, layout, components, overrides, utilities;
CamadaResponsabilidadeExemplo de conteúdo
vendorCSS de terceiros (datepickers, editores rich text)datepicker.css,

Leia o artigo completo em https://www.vivodecodigo.com.br/react/css-cascade-layers-especificidade-sem-gambiarras

Carregando publicação patrocinada...