Pular para o conteúdo principal

Formatar CSS

O Formatador de CSS reindenta e minifica uma folha de estilo no seu navegador. Ele tokeniza em vez de parsear, e é isso que permite que at-rules desconhecidas e sintaxe mais nova que a ferramenta passem intactas — um parser rejeita o que não reconhece, e, para um formatador, preservar algo que não entende é sempre melhor do que apagar.

Só local
Recuo
CSS
0 B1 linhaLin. 1, Col. 1
Formatadosomente leitura
0 B1 linha

Como funciona o Formatar CSS?

Formatar CSS é, na maior parte, saber onde uma coisa começa e termina — e há quatro lugares em que a resposta ingênua está errada.

Uma chave nem sempre é um bloco

content: "}" contém uma chave de fechamento dentro de uma string, e /* } */ contém uma dentro de um comentário. Dividir pelas chaves sem rastrear esses estados produz um formatador que estraga qualquer folha de estilo que tenha um contador de pseudo-elemento ou uma regra comentada. O exemplo acima contém os dois, de propósito.

Dois-pontos nem sempre é separador de propriedade

background: url(https://example.com/x.png) tem dois-pontos dentro do valor, e o valor de uma custom property pode conter qualquer coisa — é isso que torna as custom properties úteis. A divisão acontece no primeiro dois-pontos que não estiver dentro de parênteses.

Uma vírgula nem sempre é separador de seletores

:is(a, b) span é um seletor que contém uma vírgula, e :nth-child(2n of .x, .y) é outro. Dividir uma lista de seletores por uma vírgula solta quebra os dois. A divisão acontece apenas no nível superior, o que também mantém rgb(0, 0, 0) intacto em um valor.

Um tokenizador sobrevive a um parser

O CSS ganha sintaxe o tempo todo: nesting, @container, @layer, :has(), sintaxe de cor relativa. Um parser precisa modelar cada uma e rejeita o que não conhece — ou seja, quebra em CSS que os navegadores já aceitam. Um tokenizador só precisa saber onde estão strings, comentários, blocos e ponto e vírgula, e isso é estável desde o CSS 1. Sintaxe desconhecida passa adiante em vez de ser descartada, que é o único comportamento responsável que um formatador pode ter.

A minificação mantém um comentário de licença

/*! … */ é a convenção para um comentário que um minificador precisa preservar, e normalmente ele carrega uma licença — removê-lo pode até violar os termos sob os quais a folha de estilo foi distribuída. Todo o resto sai. O último ponto e vírgula antes de uma chave de fechamento também sai, já que separa uma declaração de nada.

O que a minificação aqui não faz é reescrever valores: nada de encurtar #ffffff para #fff, nada de mesclar regras, nada de reordenar. Essas são vantagens reais, e é também aí que um minificador vira um compilador com superfície de bugs. Para um pipeline de build, use um minificador de verdade; esta ferramenta serve para deixar uma folha de estilo pequena o suficiente para colar.

Entrada

a,b{color:red;margin:0}

Formatado

a,
b {
  color: red;
  margin: 0;
}

Quais opções e casos-limite o Formatar CSS suporta?

Referência técnica e opções
ParâmetroTipoPadrãoComportamento e casos-limite
Indentaçãoespaços2Aplicado por nível de aninhamento, então uma regra dentro de uma media query é indentada duas vezes.
Selector por linhabooleanoonCada seletor em uma lista separada por vírgula em sua própria linha. Divide apenas no nível superior, então :is(a, b) permanece intacto.
Linha em branco entre regrasbooleanoonUma linha em branco após cada regra de nível superior, o que torna uma folha de estilo longa legível.
Manter comentáriosbooleanoonComentários de múltiplas linhas mantêm sua forma interna em vez de serem reformatados, porque banners de seção em arte ASCII são comuns e o reformatamento os destrói.
Stringspreservado—content: "}" contém uma chave de fechamento. Rastrear o estado da string é o que impede que isso encerre o bloco.
url()consumido inteiro—Um url() sem aspas pode conter caracteres que de outra forma seriam estruturais, incluindo dois-pontos e parênteses em um URI de dados.
Regras @aninhado—@media, @supports, @layer, @container e qualquer coisa mais recente. Regras @ desconhecidas são passadas adiante em vez de serem descartadas.
Minificarapenas espaços em branco—Colapsa espaços em branco e remove o último ponto e vírgula em um bloco. Não reescreve valores ou mescla regras — isso é trabalho de uma etapa de build, não de uma caixa de colagem.
Comentários de licença/*! … */mantidoPreservado ao minificar, por convenção que todo minificador segue. Remover um pode violar a licença que ele carrega.

Perguntas frequentes

Vai quebrar meu CSS aninhado ou minhas @container queries?

Não, e esse é justamente o motivo de tokenizar em vez de parsear. O formatador só precisa saber onde strings, comentários e blocos começam e terminam — não precisa entender o que uma at-rule significa. Sintaxe mais nova que a ferramenta passa intacta, que é o oposto do que um parser faz ao encontrar algo que não reconhece.

Por que a saída minificada ainda tem um comentário?

Porque ele começa com /*! em vez de /*. Essa é a convenção que todo minificador respeita para um comentário que precisa sobreviver, e quase sempre ele carrega uma licença — removê-lo pode violar os termos sob os quais a folha de estilo foi distribuída. Comentários de bloco comuns são removidos.

Por que a minificação economiza menos que uma ferramenta de build de verdade?

Porque esta só remove espaços em branco. Um minificador de produção também encurta cores, mescla regras duplicadas, descarta declarações sobrescritas e reescreve shorthands — cada uma dessas é uma economia real e também uma transformação que pode mudar o comportamento se errar um caso extremo. Para um pipeline de build, use um minificador de verdade; esta ferramenta serve para deixar uma folha de estilo pequena o bastante para colar em algum lugar.

Por que minha lista de seletores não foi dividida em todas as vírgulas?

Porque algumas dessas vírgulas estão dentro de uma pseudo-classe funcional. :is(.card, .panel) é um seletor que por acaso contém uma vírgula, e dividir ali produz dois seletores que são ambos inválidos. A divisão acontece apenas no nível superior — a mesma regra que mantém rgb(0, 0, 0) intacto em um valor.

Ele valida meu CSS?

Não. Ele formata uma folha de estilo com uma propriedade escrita errado ou um valor inválido sem reclamar, porque um formatador que rejeitasse propriedades desconhecidas rejeitaria todo vendor prefix e todo recurso novo. Se você precisa de validação, o próprio DevTools do navegador sinaliza propriedades desconhecidas no painel Styles, o que é um sinal mais confiável do que qualquer lista estática.

Minha folha de estilo é enviada?

Não. A tokenização e a formatação rodam no seu navegador. Isso importa menos para CSS do que para um payload, mas importa em parte: a folha de estilo de um produto ainda não lançado descreve o produto, e a folha de estilo de uma ferramenta interna descreve a ferramenta interna.