Formatear CSS
El formateador de CSS reindenta y minifica una hoja de estilos en tu navegador. Tokeniza en lugar de analizar la sintaxis, y eso es lo que permite que las at-rules desconocidas y la sintaxis más nueva que la herramienta pasen sin cambios —un analizador rechaza lo que no reconoce y, para un formateador, conservar algo que no entiende siempre es mejor que borrarlo.
¿Cómo funciona Formatear CSS?
Dar formato a CSS consiste sobre todo en saber dónde empieza y dónde termina cada cosa, y hay cuatro lugares donde la respuesta ingenua se equivoca.
Una llave no siempre es un bloque
content: "}" contiene una llave de cierre dentro de una cadena, y /* } */ contiene otra dentro de un comentario. Partir por las llaves sin seguir esos estados produce un formateador que destroza cualquier hoja de estilos que lleve dentro un contador de pseudo-elemento o una regla comentada. El ejemplo de arriba contiene ambas cosas, a propósito.
Dos puntos no siempre separan una propiedad de su valor
background: url(https://example.com/x.png) lleva dos puntos dentro del valor, y el valor de una custom property puede contener cualquier cosa —eso es justo lo que las hace útiles—. La división se hace en los primeros dos puntos que no estén dentro de paréntesis.
Una coma no siempre separa selectores
:is(a, b) span es un selector que contiene una coma, y :nth-child(2n of .x, .y) es otro. Partir una lista de selectores por una coma cualquiera rompe ambos. La división es solo en el nivel superior, lo que además mantiene intacto rgb(0, 0, 0) dentro de un valor.
Un tokenizador dura más que un analizador
CSS gana sintaxis constantemente: anidamiento, @container, @layer, :has(), sintaxis de color relativo. Un analizador tiene que modelar cada una y rechaza todo lo que no conoce, con lo que falla ante CSS que los navegadores ya aceptan. Un tokenizador solo necesita saber dónde están las cadenas, los comentarios, los bloques y los puntos y coma, y eso lleva estable desde CSS 1. La sintaxis desconocida se deja pasar en lugar de descartarse, que es el único comportamiento del que un formateador puede hacerse responsable.
La minificación conserva un comentario de licencia
/*! … */ es la convención para un comentario que un minificador debe conservar, y normalmente lleva una licencia —quitarlo puede llegar a incumplir los términos bajo los que se distribuyó la hoja de estilos—. Todo lo demás se elimina. El último punto y coma antes de una llave de cierre también, ya que separa una declaración de nada.
Lo que la minificación de aquí no hace es reescribir valores: no acorta #ffffff a #fff, no fusiona reglas, no reordena. Son ventajas reales, y también el punto donde un minificador se convierte en un compilador con superficie de errores. Para un pipeline de build, usa un minificador de verdad; esto es para dejar una hoja de estilos lo bastante pequeña como para pegarla.
Entrada
a,b{color:red;margin:0}Formateado
a,
b {
color: red;
margin: 0;
}¿Qué opciones y casos límite admite Formatear CSS?
| Parámetro | Tipo | Valor predeterminado | Comportamiento y casos límite |
|---|---|---|---|
| Sangría | espacios | 2 | Se aplica por nivel de anidamiento, por lo que una regla dentro de una media query se sangra dos veces. |
| Selector por línea | booleano | on | Cada selector en una lista separada por comas va en su propia línea. Solo divide en el nivel superior, por lo que :is(a, b) permanece intacto. |
| Línea en blanco entre reglas | booleano | on | Una línea en blanco después de cada regla de nivel superior, lo que hace que una hoja de estilo larga sea escaneable. |
| Mantener comentarios | booleano | on | Los comentarios de varias líneas mantienen su forma interna en lugar de ser reflujo, porque las pancartas de sección en arte ASCII son comunes y el reflujo las destruye. |
| Cadenas | se conservan | — | content: "}" contiene una llave de cierre. Seguir el estado de la cadena es lo que evita que eso termine el bloque. |
| url() | se consume entero | — | Una url() entrecomillada puede contener caracteres que de otro modo serían estructurales, incluyendo dos puntos y paréntesis en un URI de datos. |
| Reglas de arroba | anidadas | — | @media, @supports, @layer, @container y cualquier cosa más nueva. Las reglas de arroba desconocidas se pasan tal cual en lugar de ser eliminadas. |
| Minificar | solo espacios en blanco | — | Contrae los espacios en blanco y elimina el punto y coma final en un bloque. No reescribe valores ni fusiona reglas: eso es trabajo de un paso de compilación, no de un área de pegado. |
| Comentarios de licencia | /*! … */ | se conservan | Se conservan al minificar, según la convención que sigue cada minificador. Eliminar uno puede infringir la licencia que lleva. |
Preguntas frecuentes
¿Romperá mi CSS anidado o mis consultas @container?
No, y para eso sirve tokenizar en lugar de analizar. El formateador solo necesita saber dónde empiezan y terminan las cadenas, los comentarios y los bloques —no necesita entender qué significa una at-rule—. La sintaxis más nueva que la herramienta pasa sin cambios, que es justo lo contrario de lo que hace un analizador cuando se encuentra algo que no reconoce.
¿Por qué la salida minificada todavía lleva un comentario?
Porque empieza con /*! en lugar de con /*. Esa es la convención que todo minificador respeta para un comentario que tiene que sobrevivir, y casi siempre lleva una licencia —quitarlo puede incumplir los términos bajo los que se distribuyó la hoja de estilos—. Los comentarios de bloque ordinarios se eliminan.
¿Por qué minificar aquí ahorra menos que una herramienta de build de verdad?
Porque esto solo elimina espacios en blanco. Un minificador de producción además acorta colores, fusiona reglas duplicadas, quita declaraciones anuladas y reescribe propiedades shorthand —cada cosa es un ahorro genuino y también una transformación que puede cambiar el comportamiento si se equivoca en un caso raro—. Para un pipeline de build usa un minificador de verdad; esto es para dejar una hoja de estilos lo bastante pequeña como para pegarla en algún sitio.
¿Por qué mi lista de selectores no se partió en cada coma?
Porque algunas de esas comas están dentro de una pseudo-clase funcional. :is(.card, .panel) es un selector que por casualidad contiene una coma, y partir ahí produce dos selectores que son ambos inválidos. La división es solo en el nivel superior —la misma regla que mantiene intacto rgb(0, 0, 0) dentro de un valor—.
¿Valida mi CSS?
No. Formateará una hoja de estilos con una propiedad mal escrita o un valor inválido sin quejarse, porque un formateador que rechazara propiedades desconocidas rechazaría todos los prefijos de proveedor y todas las funciones nuevas. Si necesitas validación, las DevTools del propio navegador marcan las propiedades desconocidas en el panel Styles, que es una señal más fiable que cualquier lista estática.
¿Se sube mi hoja de estilos?
No. Tokenizar y dar formato se ejecutan en tu navegador. Importa menos en CSS que con una carga de datos, pero importa algo: la hoja de estilos de un producto aún no lanzado describe el producto, y la de una herramienta interna describe la herramienta interna.