wandres.dev
LA CASCADA · Origen, importancia, capas, especificidad

!important y la inversión que casi nadie conoce

Qué hace exactamente la marca de importancia, qué dos criterios invierte, cuál no invierte, y por qué un !important sin capa es el más débil de todos.

⏱ 17 min

!important se enseña como si fuera un martillo: la manera de ganar cuando no sabes por qué pierdes. Ese modelo es falso y produce código que se atasca. Lo que hace en realidad es mover la declaración a la mitad superior de la tabla de precedencia, donde el orden de autoridad está invertido, y esa inversión no afecta solo a los orígenes: afecta también a las capas en cascada y a los contextos de encapsulación. Comprenderla completa cambia el uso: de recurso desesperado a herramienta con casos concretos.

🎯 Al terminar esta lección sabrás
  • Describir el efecto de !important en términos de la lista de origen e importancia.
  • Predecir el ganador entre dos declaraciones importantes en capas distintas.
  • Identificar el único escalón de la cascada que la importancia no invierte.
  • Decidir con criterio cuándo una declaración importante es legítima.

Qué hace exactamente

La marca se escribe al final del valor y antes del punto y coma, y afecta solo a esa declaración, no a la regla entera:

.aviso {
  color: crimson !important;   /* importante */
  background: white;           /* normal */
}

En una propiedad abreviada la importancia se propaga a todas las propiedades individuales que expande, lo que la hace más destructiva de lo que parece: margin: 0 !important marca como importantes los cuatro márgenes, incluidos los tres que no te interesaban.

Su efecto en el algoritmo es exactamente uno: la declaración deja de competir en los escalones 5 a 8 de la tabla de origen e importancia y pasa a competir en los escalones 2 a 4. Nada más. No cambia la especificidad, no salta ningún criterio y no gana automáticamente: entre dos declaraciones importantes del mismo origen y la misma capa, la comparación sigue bajando a la especificidad y al orden como siempre.

Esto ya desmonta el uso más común. Poner !important para ganarle a otra declaración tuya que también es importante no hace nada; solo has movido la pelea de sitio.

La doble inversión

Lo interesante de la mitad superior es que el orden de autoridad se da la vuelta, y no en un sitio sino en tres.

Se invierten los orígenes. En condiciones normales autor vence a usuario y usuario vence a navegador. Con importancia, navegador vence a usuario y usuario vence a autor. Es el mecanismo que garantiza que las necesidades de accesibilidad de una persona puedan imponerse sobre el diseño de un sitio.

Se invierten los contextos de encapsulación. Una declaración normal del documento externo vence a una del árbol de sombra interior; una importante del interior vence a una del exterior. Así un componente puede ofrecer valores por defecto fáciles de sobrescribir y a la vez imponer los que no admiten discusión.

Y se invierten las capas. Esta es la que casi nadie conoce y la que produce resultados desconcertantes. Para declaraciones normales gana la capa más tardía en el orden de capas; para declaraciones importantes gana la más temprana.

@layer base, tema;

@layer base {
  .boton { color: red; }
}

@layer tema {
  .boton { color: blue; }
}

Aquí gana blue: tema se declaró después, y para declaraciones normales manda la capa posterior. Ahora marca las dos como importantes:

@layer base, tema;

@layer base {
  .boton { color: red !important; }
}

@layer tema {
  .boton { color: blue !important; }
}

Ahora gana red. La capa base, que en condiciones normales era la más débil, es la más fuerte cuando ambas insisten. El motivo es de diseño y es coherente: la inversión sigue exactamente la misma lógica que con los orígenes, de modo que !important conserva en los dos sitios el mismo significado, que es “esto no se negocia”.

Un !important fuera de toda capa es el más débil de todos los importantes

Ata los dos cabos anteriores y sale un resultado que contradice frontalmente la intuición de todo el mundo. Las declaraciones que no están dentro de ninguna capa se tratan, a efectos del criterio de capas, como si estuvieran en una capa implícita situada al final del orden. Para declaraciones normales eso las hace fortísimas: tu CSS sin capas gana a cualquier CSS que esté dentro de una capa, sin importar el selector. Pero aplícale ahora la inversión: si la comparación es entre declaraciones importantes, gana la capa más temprana, y la capa implícita está en el último lugar. Conclusión: un !important escrito fuera de toda capa pierde contra un !important escrito dentro de cualquier capa. La primera vez que te topas con esto en un proyecto real parece un fallo del navegador. No lo es, y tiene una aplicación práctica excelente: si quieres construir una capa de utilidades que gane siempre, no la pongas al final como haría el instinto, ponla la primera del orden de capas y marca sus declaraciones como importantes. Sus reglas normales serán las más débiles del sistema, que es lo que quieres para las que no insisten, y sus reglas importantes serán las más fuertes, que es lo que quieres de una utilidad que existe precisamente para forzar un valor concreto. Es exactamente lo que hacen los sistemas de utilidades modernos, y es la única configuración en la que !important deja de ser deuda y pasa a ser una decisión de arquitectura documentada.

Lo único que no se invierte

Hay un escalón de la cascada donde la importancia no da la vuelta a nada, y merece la pena tenerlo claro porque es fuente de discusiones: el atributo style.

La especificación dice que la comparación entre declaraciones pegadas al elemento y declaraciones que llegan por selector se hace por separado para normales y para importantes, y que en ambos casos gana la pegada al elemento. Es decir, un style="color: red !important" en el HTML vence a un .x { color: blue !important } de tu hoja de estilos, igual que la versión sin importancia vence a la versión sin importancia.

<p style="color: red !important">Este párrafo sale rojo</p>
/* Pierde, aunque sea importante y el selector tenga especificidad alta */
body p.destacado { color: blue !important; }

La consecuencia operativa es dura y conviene aceptarla: si un script está escribiendo estilos importantes en el atributo style, desde CSS de autor no hay forma de ganarle. No es cuestión de encontrar el selector correcto: el criterio que decide está por encima de la especificidad y ya se resolvió. La salida pasa por dejar de escribir ahí, y esa es una conversación con el código de JavaScript, no con la hoja de estilos.

Cuándo es legítimo

Hay cuatro situaciones en las que una declaración importante es la respuesta correcta y no una rendición.

Una capa de utilidades declarada la primera, por lo explicado en el recuadro anterior. Aquí la importancia es intencionada, está acotada a un bloque conocido y se documenta como parte del sistema.

Estilos de usuario. Es el uso para el que se diseñó. Si escribes una hoja de usuario para tu propia necesidad, !important es la herramienta.

Ganar a estilos en línea que no controlas, con el matiz de que solo funciona si esos estilos en línea no son importantes. Contra un style importante no hay nada que hacer desde CSS.

Hojas de impresión, donde a menudo hay que anular con brocha gorda un diseño de pantalla completo y el ciclo de vida de esas reglas es corto y aislado.

Fuera de esos cuatro casos, un !important casi siempre es el síntoma de haber intentado expresar autoridad con la herramienta equivocada. La pregunta que conviene hacerse antes de escribirlo es concreta: ¿estoy perdiendo por especificidad o por orden? Si es por especificidad, el arreglo es igualar o bajar selectores, o meter lo que pierde en una capa. Si es por orden, el arreglo es mover el fichero. En los dos casos el resultado es un sistema donde alguien podrá sobrescribirte mañana sin escalar; con !important el techo queda cerrado y el siguiente que llegue no tendrá más remedio que escalar él.

Y una advertencia sobre las custom properties, porque su comportamiento aquí sorprende: la importancia se aplica a la declaración de la variable, no a su uso. --color: red !important fija con importancia el valor de la variable, pero la propiedad que después hace color: var(--color) sigue siendo una declaración normal y cualquiera puede ganarle. Marcar variables como importantes crea sistemas que no se pueden tematizar y es de las decisiones más difíciles de deshacer después.