A proposta é de 2024 e era de Lea Verou: deixar o CSS selecionar todas as classes que começam com um prefixo, sem precisar listar uma por uma nem inventar classe base. No encontro presencial do CSS Working Group em Berlim, em agosto de 2026, a ideia foi resolvida, e o texto já está no Editor’s Draft de Selectors Level 5 de 18 de agosto.
A forma é curta e parece resolver o problema inteiro:
.btn-* {
border-radius: 4px;
}
A posição deste post: antes de trocar o seu design system por isso, leia a regra de casamento com atenção. Ela tem uma restrição de hífen que exclui metade do BEM, e o separador que a outra metade usa nem está na especificação.
O que o seletor faz, exatamente
A definição do rascunho é literal: um ponto final, seguido imediatamente de um identificador que termina em um ou mais hifens, seguido imediatamente de um asterisco. É por isso que .foo-* é válido e .foo* não é. Este último nem vira erro: o parser lê como um seletor de classe .foo colado ao seletor universal, e você fica com uma regra que não faz o que você acha.
O casamento acontece quando a classe começa com o prefixo, existe pelo menos um caractere depois dele, e esse primeiro caractere não é outro hífen. Os exemplos do próprio texto deixam a regra clara:
class="foo-bar-baz" casa com .foo-* e com .foo-bar-*
class="foo--bar" casa com .foo--* e NAO casa com .foo-*
class="foo-bar-" NAO casa com .foo-bar-*
Repare na linha do meio. Ela é a que muda o seu dia.
A regra do hífen duplo é a que pega o BEM
Em BEM, o modificador é o hífen duplo. Um cartão em destaque é card--destacado, e um botão desabilitado é btn--disabled. Pela regra acima, .card-* não alcança card--destacado, porque o caractere logo depois do prefixo card- é outro hífen. Para pegar o modificador você precisa escrever o prefixo com os dois hifens: .card--*.
Isso é defensável do lado da especificação, e é chato do lado de quem escreve. Significa que uma folha de estilo BEM não ganha um seletor, ganha dois, um para o bloco e outro para o modificador.
A outra metade do BEM é pior. O elemento usa sublinhado duplo: card__titulo. Como o seletor exige que o identificador termine em hífen, não existe .card__* válido. O texto do rascunho registra que outros separadores, como o sublinhado, podem ser adicionados no futuro. Podem. Hoje não estão.
Ou seja, para a convenção de nomes mais usada em CSS componentizado, o recurso cobre o bloco, cobre o modificador com um segundo seletor, e não cobre o elemento. Quem sai ganhando de verdade é o mundo utilitário, onde tudo já é text-, bg-, gap- e col-span-, com um hífen só e nenhum sublinhado.
O que você usa hoje, e por que continua ruim
A alternativa atual é seletor de atributo por substring, e ela erra em duas direções.
[class*="btn-"] casa tambem com "nao-btn-primario"
[class~="btn-"] nao casa com nada, porque ~= exige o token inteiro
[class*=" btn-"] depende do espaco, entao perde a primeira classe do atributo
A terceira linha é a que costuma aparecer em código de produção, com uma classe vazia adicionada no começo do atributo para compensar. Funciona por acidente de formatação e quebra quando alguém normaliza o HTML.
Existe ainda o caminho conhecido: criar a classe base. Você escreve class="btn btn-primary" e estiliza .btn. Continua sendo a solução correta hoje, e o custo dela é o que a proposta original citava, bytes repetidos em todo elemento e uma classe que existe só para o CSS conseguir mirar.
Por que a especificação recusou o curinga livre
A pergunta óbvia é por que não permitir .foo* e acabar com a conversa. O rascunho dá duas razões, e as duas são boas.
A primeira é seleção acidental. Um .foo* casaria com footer, e ninguém escreveu aquela regra pensando no rodapé. Exigir que o prefixo termine em separador transforma prefixo em fronteira semântica, não em coincidência de letras.
A segunda é desempenho de casamento. O navegador não testa cada regra contra cada elemento. Ele mantém estruturas de descarte rápido, entre elas filtros de Bloom montados a partir dos identificadores e das classes da árvore, para eliminar em bloco os seletores que não têm chance. Curinga arbitrário destrói essa aposta: sem fronteira definida, todo prefixo possível teria que entrar no filtro, e um filtro que aceita quase tudo deixa de descartar qualquer coisa. Prefixo terminado em hífen mantém o conjunto de chaves finito e o descarte barato.
O que ainda não está resolvido
Resolução do grupo de trabalho é o começo do processo, não o fim. Três pontos abertos merecem atenção antes de você planejar migração:
Não há implementação. Nenhuma das três engines suporta o seletor hoje. Pelo levantamento de Bramus Van Damme, existe bug de acompanhamento apenas no Chromium. Recurso que entra em rascunho editorial costuma levar de meses a anos até virar algo que dá para usar sem plano B.
A seção do rascunho não fala de especificidade. O comportamento esperado é o de um seletor de classe, com peso 0-1-0, e é isso que a leitura natural do texto sugere, mas enquanto não estiver escrito não é garantia. Especificidade é justamente o que decide se a sua regra nova vence a antiga, então esse silêncio importa.
O conjunto de separadores é declaradamente provisório. Hífen agora, talvez sublinhado depois. Uma convenção de nomes desenhada hoje para aproveitar o recurso pode estar apostando numa extensão que não vem.
O que fazer com isso agora
Nada de reescrever CSS. O que dá para fazer é barato e não depende de suporte: manter o hífen como separador de nível nas classes novas e evitar prefixo que seja apenas o começo de outra palavra do seu vocabulário. Uma base de código com card-header e card-body vai colher o recurso sem tocar em nada. Uma base com cardHeader em camelo vai ter que renomear.
E vale ajustar a expectativa do time. Este seletor não substitui design system, não substitui camada de utilitários e não elimina a classe base. Ele remove uma linha repetida do HTML e um seletor de atributo lento da folha de estilo. É útil e é pequeno, e a distância entre o que a manchete promete e o que a regra de hífen entrega é onde mora o retrabalho.
Perguntas frequentes
O seletor de prefixo funciona com Tailwind?
Funciona bem, quando existir. As classes utilitárias do Tailwind são separadas por hífen simples, então .text-*, .bg-* e .grid-cols-* casam pela regra. O caso que exige atenção é o das variantes com dois pontos, como hover:bg-blue-500, porque ali o começo da classe não é o nome do utilitário que você quer mirar.
Dá para usar dentro de :is() e :not()?
Não há nada no texto que impeça, porque o seletor de prefixo é um seletor composto comum. Como não existe implementação, qualquer afirmação sobre o comportamento combinado é leitura de rascunho, não teste.
Isso substitui a classe base do meu componente?
Não hoje, e provavelmente não amanhã. Enquanto Firefox e Safari não implementarem, remover a classe base quebra o site nesses navegadores. Quando implementarem, ainda vai existir o caso de estilo que se aplica ao componente inteiro independente da variante, que é exatamente para o que a classe base serve.
Fontes