Especificidad

Supongamos que estás trabajando con el siguiente código HTML y CSS:

<button class="branding">Hello, Specificity!</button>
.branding {
  color: blue;
}

button {
  color: red;
}

Aquí hay dos reglas que se orientan al mismo elemento. Cada regla contiene una declaración que desea establecer el color del botón: una intenta pintarlo de rojo y la otra de azul. ¿Qué declaración se aplica al elemento?

Comprender el algoritmo de especificidad de CSS es clave para entender cómo CSS decide entre declaraciones en competencia.

La especificidad es una de las etapas distintas de la cascada, que se analizó en el último módulo, sobre la cascada.

Puntuación de especificidad

Cada regla de selector dentro de un origen obtiene una puntuación. Puedes considerar la especificidad como una puntuación total, y cada tipo de selector obtiene puntos para esa puntuación. Las declaraciones de las reglas con la mayor especificidad prevalecen.

Con la especificidad de un proyecto real, el equilibrio consiste en asegurarse de que las reglas de CSS que esperas aplicar se apliquen, mientras que, en general, se mantienen las puntuaciones bajas para evitar la complejidad. La especificidad solo debe ser tan alta como la necesitemos, en lugar de buscar la más alta posible. En el futuro, es posible que debas aplicar algunos CSS realmente más importantes. Si buscas la especificidad más alta, dificultarás esa tarea.

La especificidad no es un número decimal, sino una tríada que consta de tres componentes: A, B y C.

  • A: Especificidad similar a un ID
  • B: Especificidad similar a la clase
  • C: Especificidad similar a un elemento

A menudo, se representa con la notación (A,B,C). Por ejemplo: (1,0,2). También se usa con frecuencia la notación alternativa A-B-C.

Un diagrama que muestra los tres componentes de la especificidad (A, B y C). Para cada componente, el diagrama muestra lo que representa y algunos selectores de ejemplo que lo afectan.
Diagrama que muestra qué componente de especificidad afectan varios selectores.

Comparación de especificaciones

Para comparar las especificidades, se comparan los tres componentes en orden: la especificidad con un valor A más alto es más específica; si los dos valores A están empatados, la especificidad con un valor B más alto es más específica; si los dos valores B también están empatados, la especificidad con un valor C más alto es más específica; si todos los valores están empatados, las dos especificidades son iguales.

Por ejemplo, (1,0,0) se considera una especificidad más alta que (0,4,3) porque el valor de A en (1,0,0) (que es 1) es mayor que el valor de A de (0,4,3) (que es 0).

Los selectores influyen en la especificidad

Cada parte de la tríada de especificidad comienza con un valor de 0, por lo que la especificidad predeterminada es (0,0,0). Cada parte de un selector aumenta la especificidad que, según el tipo de selector, incrementa el valor de A, B o C.

Selector universal

Un selector universal (*) no agrega especificidad, por lo que su valor se mantiene en la especificidad inicial de (0,0,0).

* {
  color: red;
}

Selector de elemento o pseudoelemento

Un selector de elemento (tipo) o pseudoelemento agrega especificidad similar a un elemento, que incrementa el componente C en 1.

Los siguientes ejemplos tienen una especificidad general de (0,0,1).

Selector de tipo

div {
  color: red;
}

Selector de pseudoelementos

::selection {
  color: red;
}

Selector de clase, pseudoclase o atributo

Un selector de clase, pseudoclase o atributo agrega especificidad similar a la clase, que incrementa el componente B en 1.

Los siguientes ejemplos tienen una especificidad de (0,1,0).

Selector de clases

.my-class {
  color: red;
}

Selector de pseudoclase

:hover {
  color: red;
}

Selector de atributos

[href='#'] {
  color: red;
}

Selector de ID

Un selector de ID agrega especificidad similar a un ID, que incrementa el componente C en 1, siempre y cuando uses un selector de ID (#myID) y no un selector de atributos ([id="myID"]).

En el siguiente ejemplo, la especificidad es (1,0,0).

#myID {
  color: red;
}

Otros selectores

CSS tiene muchos selectores. No todos agregan especificidad. Por ejemplo, la pseudoclase :not() en sí no agrega nada al cálculo de especificidad.

Sin embargo, los selectores que se pasan como argumentos se agregan al cálculo de especificidad.

div:not(.my-class) {
  color: red;
}

Este ejemplo tiene una especificidad de (0,1,1) porque tiene un selector de tipo (div) y una clase dentro de :not().

Verifica tu comprensión

Pon a prueba tus conocimientos sobre la puntuación de especificidad

¿Cuál es la especificidad de a[href="#"]?

(0,1,0)
(0,0,1)
(0,1,1)

Factores que no afectan la especificidad

Existen algunos conceptos erróneos comunes sobre los siguientes factores que afectan la especificidad.

Atributos de estilo intercalado

El CSS aplicado directamente al atributo style de un elemento no afecta la especificidad, ya que es un paso diferente en la cascada que se evalúa antes de la especificidad.

<div style="color: red"></div>

Para anular esta declaración desde una hoja de estilo, debes recurrir a obtener la victoria de la declaración en un paso anterior de la cascada.

Por ejemplo, podrías agregar !important para que forme parte del origen de !important creado por el autor.

Declaraciones de !important

Un !important al final de una declaración de CSS no afecta la especificidad, pero coloca la declaración en un origen diferente, es decir, !important creado por el autor.

En el siguiente ejemplo, la especificidad de .my-class no es relevante para que la declaración !important prevalezca.

.my-class {
  color: red !important;
  color: white;
}

Cuando dos declaraciones son !important, la especificidad vuelve a entrar en juego, ya que el paso de origen de la cascada aún no pudo determinar el ganador.

.branding {
  color: blue !important;
}

button {
  color: red !important;
}

Especificidad en contexto

Cuando se usa un selector complejo o compuesto, cada parte de ese selector se suma a la especificidad. Considera el siguiente ejemplo de HTML:

<a class="my-class another-class" href="#">A link</a>

Este vínculo tiene dos clases. La regla en el siguiente CSS tiene una especificidad de (0,0,1):

a {
  color: red;
}

Si haces referencia a una de las clases en el selector, ahora tiene una especificidad de (0,1,1):

a.my-class {
  color: green;
}

Agrega la otra clase al selector, ahora tiene una especificidad de (0,2,1):

a.my-class.another-class {
  color: rebeccapurple;
}

Agrega el atributo href al selector, ahora tiene una especificidad de (0,3,1):

a.my-class.another-class[href] {
  color: goldenrod;
}

Por último, agrega una pseudoclase :hover a todo eso. El selector termina con una especificidad de (0,4,1):

a.my-class.another-class[href]:hover {
  color: lightgrey;
}

Verifica tu comprensión

Pon a prueba tus conocimientos sobre la puntuación de especificidad

¿Cuál de los siguientes selectores tiene una especificidad de (0,2,1)?

article:hover a[href]
article.card.dark
article > section

Aumenta la especificidad de forma pragmática

Supongamos que tienes un CSS que se ve de la siguiente manera:

.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

Con HTML que se ve de la siguiente manera:

<button class="my-button" onclick="alert('hello')">Click me</button>

El botón tiene un fondo gris porque el segundo selector tiene una especificidad de (0,1,1). Esto se debe a que tiene un selector de tipo (button), que es (0,0,1), y un selector de atributos ([onclick]), que es (0,1,0).

La regla anterior (.my-button) es igual a (0,1,0) porque tiene un selector de clase, que tiene una especificidad más baja que (0,1,1).

Si quieres mejorar esta regla, puedes repetir el selector de clase de la siguiente manera:

.my-button.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

Ahora, el botón tendrá un fondo azul, porque el nuevo selector obtiene una especificidad (0,2,0).

Si hay un empate en la especificidad, se pasa al siguiente paso de la cascada.

Por ahora, quedémonos con el ejemplo del botón y cambiemos el CSS a lo siguiente:

.my-button {
  background: blue;
}

[onclick] {
  background: grey;
}

El botón tiene un fondo gris porque ambos selectores tienen una especificidad idéntica de (0,1,0).

Si cambias las reglas en el orden de la fuente, el botón será azul.

[onclick] {
  background: grey;
}

.my-button {
  background: blue;
}

Esto se debe a que ambos selectores tienen la misma especificidad. En este caso, la cascada recurre a el paso de orden de aparición.

Recursos